From 0d8b3f09af6c9ca797ebc691e1d5f4da741128ca Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Tue, 5 Dec 2023 14:42:06 -0500 Subject: [PATCH] Provide guidance for renaming classes in polymorphic associations [ci skip] Add guidance to the Association Basics and `.belongs_to` method documentation to encourage the renaming of a model's Ruby class to coincide with updates to the existing data in the database. Since Action Text and Active Storage rely on polymorphic associations, add similar warnings to their guides. Co-authored-by: Petrik de Heus Co-authored-by: Stephen Hanson Co-authored-by: zzak --- actiontext/lib/action_text/attribute.rb | 5 +++++ activerecord/lib/active_record/associations.rb | 2 ++ activestorage/lib/active_storage/attached/model.rb | 8 ++++++++ guides/source/action_text_overview.md | 2 ++ guides/source/active_storage_overview.md | 3 +++ guides/source/association_basics.md | 5 +++++ 6 files changed, 25 insertions(+) diff --git a/actiontext/lib/action_text/attribute.rb b/actiontext/lib/action_text/attribute.rb index 9daf042f07..96a34928c4 100644 --- a/actiontext/lib/action_text/attribute.rb +++ b/actiontext/lib/action_text/attribute.rb @@ -34,6 +34,11 @@ module Attribute # * :strict_loading - Pass true to force strict loading. When # omitted, strict_loading: will be set to the value of the # strict_loading_by_default class attribute (false by default). + # + # Note: Action Text relies on polymorphic associations, which in turn store class names in the database. + # When renaming classes that use has_rich_text, make sure to also update the class names in the + # action_text_rich_texts.record_type polymorphic type column of + # the corresponding rows. def has_rich_text(name, encrypted: false, strict_loading: strict_loading_by_default) class_eval <<-CODE, __FILE__, __LINE__ + 1 def #{name} diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index fa01581066..2bf02acb3e 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1825,6 +1825,8 @@ def has_one(name, scope = nil, **options) # Specify this association is a polymorphic association by passing +true+. # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). + # Note: Since polymorphic associations rely on storing class names in the database, make sure to update the class names in the + # *_type polymorphic type column of the corresponding rows. # [+:validate+] # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default. # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. diff --git a/activestorage/lib/active_storage/attached/model.rb b/activestorage/lib/active_storage/attached/model.rb index f848d87e69..30b7663914 100644 --- a/activestorage/lib/active_storage/attached/model.rb +++ b/activestorage/lib/active_storage/attached/model.rb @@ -97,6 +97,10 @@ module Attached::Model # has_one_attached :avatar, strict_loading: true # end # + # Note: Active Storage relies on polymorphic associations, which in turn store class names in the database. + # When renaming classes that use has_one_attached, make sure to also update the class names in the + # active_storage_attachments.record_type polymorphic type column of + # the corresponding rows. def has_one_attached(name, dependent: :purge_later, service: nil, strict_loading: false) ActiveStorage::Blob.validate_service_configuration(service, self, name) unless service.is_a?(Proc) @@ -188,6 +192,10 @@ def #{name}=(attachable) # has_many_attached :photos, strict_loading: true # end # + # Note: Active Storage relies on polymorphic associations, which in turn store class names in the database. + # When renaming classes that use has_many, make sure to also update the class names in the + # active_storage_attachments.record_type polymorphic type column of + # the corresponding rows. def has_many_attached(name, dependent: :purge_later, service: nil, strict_loading: false) ActiveStorage::Blob.validate_service_configuration(service, self, name) unless service.is_a?(Proc) diff --git a/guides/source/action_text_overview.md b/guides/source/action_text_overview.md index cfdda000b4..e558d37d48 100644 --- a/guides/source/action_text_overview.md +++ b/guides/source/action_text_overview.md @@ -106,6 +106,8 @@ class MessagesController < ApplicationController end ``` +NOTE: Since Action Text relies on polymorphic associations, and [polymorphic associations](./association_basics.html#polymorphic-associations) rely on storing class names in the database, that data must remain synchronized with the class name used by the Ruby code. When renaming classes that use `has_rich_text`, make sure to also update the class names in the `action_text_rich_texts.record_type` polymorphic type column of the corresponding rows. + [`rich_text_area`]: https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-rich_text_area ## Rendering Rich Text Content diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 0119a69dd5..0ed558b8e1 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -475,6 +475,8 @@ end Rails will enqueue a job to generate the variant after the attachment is attached to the record. +NOTE: Since Active Storage relies on polymorphic associations, and [polymorphic associations](./association_basics.html#polymorphic-associations) rely on storing class names in the database, that data must remain synchronized with the class name used by the Ruby code. When renaming classes that use `has_one_attached`, make sure to also update the class names in the `active_storage_attachments.record_type` polymorphic type column of the corresponding rows. + [`has_one_attached`]: https://api.rubyonrails.org/classes/ActiveStorage/Attached/Model.html#method-i-has_one_attached [Attached::One#attach]: https://api.rubyonrails.org/classes/ActiveStorage/Attached/One.html#method-i-attach [Attached::One#attached?]: https://api.rubyonrails.org/classes/ActiveStorage/Attached/One.html#method-i-attached-3F @@ -549,6 +551,7 @@ end [Attached::Many#attach]: https://api.rubyonrails.org/classes/ActiveStorage/Attached/Many.html#method-i-attach [Attached::Many#attached?]: https://api.rubyonrails.org/classes/ActiveStorage/Attached/Many.html#method-i-attached-3F +NOTE: Since Active Storage relies on polymorphic associations, and [polymorphic associations](./association_basics.html#polymorphic-associations) rely on storing class names in the database, that data must remain synchronized with the class name used by the Ruby code. When renaming classes that use `has_many_attached`, make sure to also update the class names in the `active_storage_attachments.record_type` polymorphic type column of the corresponding rows. ### Attaching File/IO Objects diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index c1b5bfaf13..09a79dc876 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -538,6 +538,11 @@ class CreatePictures < ActiveRecord::Migration[7.2] end ``` +NOTE: Since polymorphic associations rely on storing class names in the +database, that data must remain synchronized with the class name used by the +Ruby code. When renaming a class, make sure to update the data in the +polymorphic type column. + ![Polymorphic Association Diagram](images/association_basics/polymorphic.png) ### Associations between Models with Composite Primary Keys