{"record":{"id":"ca733439045409ce","repo":"paper-trail-gem/paper_trail","slug":"passing-version-class-name-as-has-paper-trail-cla","errorCode":null,"errorMessage":"Passing Version class name as `has_paper_trail class_name: %{class_name}` is deprecated. Use `has_paper_trail versions: {class_name: %{class_name}}` instead. The hash you pass to `versions:` is now passed directly to `has_many`.","messagePattern":"Passing Version class name as `has_paper_trail class_name: %(.+?)` is deprecated\\. Use `has_paper_trail versions: (.+?)\\}` instead\\. The hash you pass to `versions:` is now passed directly to `has_many`\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"lib/paper_trail/model_config.rb","lineNumber":159,"sourceCode":"    def assert_valid_recording_order_for_on_destroy(recording_order)\n      unless %w[after before].include?(recording_order.to_s)\n        raise ArgumentError, 'recording order can only be \"after\" or \"before\"'\n      end\n\n      if recording_order.to_s == \"after\" && cannot_record_after_destroy?\n        raise Error, E_CANNOT_RECORD_AFTER_DESTROY\n      end\n    end\n\n    def cannot_record_after_destroy?\n      ::ActiveRecord::Base.belongs_to_required_by_default\n    end\n\n    def check_version_class_name(options)\n      # @api private - `version_class_name`\n      @model_class.class_attribute :version_class_name\n      if options[:class_name]\n        PaperTrail.deprecator.warn(\n          format(\n            DPR_CLASS_NAME_OPTION,\n            class_name: options[:class_name].inspect\n          ),\n          caller(1)\n        )\n        options[:versions][:class_name] = options[:class_name]\n      end\n      @model_class.version_class_name = options[:versions][:class_name] || \"PaperTrail::Version\"\n      assert_concrete_activerecord_class(@model_class.version_class_name)\n    end\n\n    def check_versions_association_name(options)\n      # @api private - versions_association_name\n      @model_class.class_attribute :versions_association_name\n      @model_class.versions_association_name = options[:versions][:name] || :versions\n    end\n","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/paper-trail-gem/paper_trail/blob/098058ae472d13763fe66e6866a6a4dfc64a3eca/lib/paper_trail/model_config.rb#L141-L177","documentation":"has_paper_trail's old `class_name:` option (used to point a host model at a custom Version class) was replaced by the `versions:` hash. check_version_class_name in lib/paper_trail/model_config.rb:159 detects `options[:class_name]`, warns via PaperTrail.deprecator, then copies the value into `options[:versions][:class_name]` so behavior is unchanged for now. The `versions:` hash is now passed straight to `has_many`, so the old flat key will be removed in a future PT release — code relying on it will then silently fall back to PaperTrail::Version or raise.","triggerScenarios":"Declaring a host model with `has_paper_trail class_name: \"MyVersion\"` (or passing `class_name:` inside has_paper_trail options in any form) on paper_trail 11+/12+. Fires once per model class at boot time when ModelConfig#check_version_class_name runs, with caller(1) pointing at the offending model file.","commonSituations":"Apps upgrading from paper_trail < 11 (where `class_name:` was the documented syntax for Custom Version Classes) to PT 11/12+; old initializers or gems that configure `has_paper_trail class_name:` on behalf of models; copy-pasted blog examples predating the option reshuffle.","solutions":["Replace the flat option with the nested hash: `has_paper_trail versions: { class_name: \"MyVersion\" }`.","If you were only passing class_name to get the default, drop the option entirely — PT defaults to PaperTrail::Version.","Make deprecations loud in test/CI (`PaperTrail.deprecator.behavior = :raise`) and fix every call site before the next PT major, where the legacy key is removed."],"exampleFix":"# app/models/article.rb - before\nhas_paper_trail class_name: \"ArticleVersion\"\n\n# app/models/article.rb - after\nhas_paper_trail versions: { class_name: \"ArticleVersion\" }","handlingStrategy":"validation","validationCode":"# CI guard: fail if any model still uses the deprecated flat option\n# (run from repo root; adjust dirs to your layout)\n# grep -rn --include='*.rb' -E 'has_paper_trail[^\\n]*class_name:' app lib | grep -v 'versions:' && exit 1 || exit 0","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt the `versions: { ... }` hash form in all new code; it is forwarded verbatim to has_many, so any has_many option you need goes there.","Run tests with `PaperTrail.deprecator.behavior = :raise` so any remaining deprecated call site fails fast at boot.","After upgrading paper_trail majors, grep app/models for `has_paper_trail` and diff each option list against the current README before shipping."],"tags":["ruby","paper-trail","deprecation","activerecord","has-many"],"backgroundTag":"deprecated-option-migration","analyzedSha":"098058ae472d13763fe66e6866a6a4dfc64a3eca","analyzedAt":"2026-08-21T18:44:58.137Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}