From 880464a16a2c61e812e1725592ba355b4ba9b92c Mon Sep 17 00:00:00 2001 From: Grace Miller Date: Thu, 12 Dec 2024 15:12:00 -0500 Subject: [PATCH 1/5] DOCSP-42034-allow-custom-polymorphic-types --- source/reference/associations.txt | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/source/reference/associations.txt b/source/reference/associations.txt index e8f9c7b3..765315e6 100644 --- a/source/reference/associations.txt +++ b/source/reference/associations.txt @@ -1211,6 +1211,44 @@ that a bundle may contain other bundles or products: has_many :items, polymorphic: true end +Starting in version 9.0.2, Mongoid allows you to store an arbitrary string in the +`*_type` attribute. This feature allows the class resolution to be handled at +runtime. + +For example: + +.. code-block:: ruby + + class Item + include Mongoid::Document + belongs_to :unitable, polymorphic: true, type_field_method: + :resolve_unitable_type + field :unitable_type, type: String + + def resolve_unitable_type(value) + case value + when "warehouse" + Unit + when "store" + Store + else + nil + end + end + end + + unit = Unit.create(name: "Warehouse") + item = Item.create(unitable_id: unit.id, unitable_type: "warehouse") + + store = Store.create(name: "Downtown") + store_item = Item.create(unitable_id: store.id, unitable_type: "store") + + # Results in + # { "_id": ObjectId("..."), "unitable_id": ObjectId("..."), "unitable_type": "warehouse" } + # { "_id": ObjectId("..."), "unitable_id": ObjectId("..."), "unitable_type": "store" } + + + ``has_and_belongs_to_many`` associations do not support polymorphism. From b32d9f44c0cb70f221961794b8874590cf11ab5a Mon Sep 17 00:00:00 2001 From: Grace Miller Date: Fri, 13 Dec 2024 12:44:16 -0500 Subject: [PATCH 2/5] updated copy --- source/reference/associations.txt | 73 +++++++++++++++++++------------ 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/source/reference/associations.txt b/source/reference/associations.txt index 765315e6..8aef1204 100644 --- a/source/reference/associations.txt +++ b/source/reference/associations.txt @@ -1211,43 +1211,60 @@ that a bundle may contain other bundles or products: has_many :items, polymorphic: true end -Starting in version 9.0.2, Mongoid allows you to store an arbitrary string in the -`*_type` attribute. This feature allows the class resolution to be handled at -runtime. +Starting in version 9.0.2, Mongoid adds support to custom polymorphic types via +a global registry. You can now specify alternative keys to represent different +classes, thus decoupling the code from the data. For example: -For example: +.. code-block:: ruby + + class Department + include Mongoid::Document + identify_as 'dept' + has_many :managers, as: :unit + end + +The ``identify_as 'dept'`` directive says that this class should be identified by +the string "dept" in the database. You can specify multiple aliases, too (e.g. +``entify_as 'dept', 'div', 'agency'``), in which case the first key is the "default", +and the others are only used for looking up records. This lets you refactor your +code without breaking the associations in your data. + +Note that these aliases are global; the keys you specify must be unique across your +entire code base. However, it is possible to register alternative resolvers, which +must be used for different subsets of your models. In this case, the keys must +only be unique for each resolver. For example: .. code-block:: ruby - class Item - include Mongoid::Document - belongs_to :unitable, polymorphic: true, type_field_method: - :resolve_unitable_type - field :unitable_type, type: String - - def resolve_unitable_type(value) - case value - when "warehouse" - Unit - when "store" - Store - else - nil - end - end - end + Mongoid::ModelResolver.register_resolver Mongoid::ModelResolver.new, :eng + Mongoid::ModelResolver.register_resolver Mongoid::ModelResolver.new, :purch - unit = Unit.create(name: "Warehouse") - item = Item.create(unitable_id: unit.id, unitable_type: "warehouse") + module Engineering + class Department + include Mongoid::Document + identify_as 'dept', resolver: :eng + end - store = Store.create(name: "Downtown") - store_item = Item.create(unitable_id: store.id, unitable_type: "store") + class Manager + include Mongoid::Document + belongs_to :unit, polymorphic: :eng + end + end - # Results in - # { "_id": ObjectId("..."), "unitable_id": ObjectId("..."), "unitable_type": "warehouse" } - # { "_id": ObjectId("..."), "unitable_id": ObjectId("..."), "unitable_type": "store" } + module Purchasing + class Department + include Mongoid::Document + identify_as 'dept', resolver: :purch + end + class Manager + include Mongoid::Document + belongs_to :unit, polymorphic: :purch + end + end +Both ``Engineering::Department`` and ``Purchasing::Department`` are aliased as +``"dept"``, but use their own resolver, so there is no conflict. ``has_and_belongs_to_many`` associations do not support polymorphism. From 900dea7ac55b062a5db9f3daac9397441b748569 Mon Sep 17 00:00:00 2001 From: Grace Miller Date: Mon, 16 Dec 2024 11:48:29 -0500 Subject: [PATCH 3/5] copy edits --- source/reference/associations.txt | 36 ++++++++++++------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/source/reference/associations.txt b/source/reference/associations.txt index 8aef1204..f9981323 100644 --- a/source/reference/associations.txt +++ b/source/reference/associations.txt @@ -1211,9 +1211,10 @@ that a bundle may contain other bundles or products: has_many :items, polymorphic: true end -Starting in version 9.0.2, Mongoid adds support to custom polymorphic types via -a global registry. You can now specify alternative keys to represent different -classes, thus decoupling the code from the data. For example: +Starting in version 9.0.2, Mongoid adds support to custom polymorphic types through +a global registry. You can specify alternative keys to represent different +classes, thus decoupling the code from the data. The following example specifies +the string ``"dept"`` as an alternate key for the ``Department`` class: .. code-block:: ruby @@ -1223,16 +1224,18 @@ classes, thus decoupling the code from the data. For example: has_many :managers, as: :unit end -The ``identify_as 'dept'`` directive says that this class should be identified by -the string "dept" in the database. You can specify multiple aliases, too (e.g. -``entify_as 'dept', 'div', 'agency'``), in which case the first key is the "default", -and the others are only used for looking up records. This lets you refactor your -code without breaking the associations in your data. +The ``identify_as 'dept'`` directive instructs Mongoid to store this class in the +database as the string ``"dept"``. You can also specify multiple aliases. For +example, you can specify the option as: ``identify_as 'dept', 'div', 'agency'``, +in which case the first key is the "default", and the others are used only for +looking up records. This lets you refactor your code without breaking the associations +in your data. -Note that these aliases are global; the keys you specify must be unique across your +These aliases are global. The keys you specify must be unique across your entire code base. However, it is possible to register alternative resolvers, which must be used for different subsets of your models. In this case, the keys must -only be unique for each resolver. For example: +only be unique for each resolver. The following example shows how to register +alternate resolvers: .. code-block:: ruby @@ -1245,26 +1248,15 @@ only be unique for each resolver. For example: identify_as 'dept', resolver: :eng end - class Manager - include Mongoid::Document - belongs_to :unit, polymorphic: :eng - end - end - module Purchasing class Department include Mongoid::Document identify_as 'dept', resolver: :purch end - class Manager - include Mongoid::Document - belongs_to :unit, polymorphic: :purch - end - end Both ``Engineering::Department`` and ``Purchasing::Department`` are aliased as -``"dept"``, but use their own resolver, so there is no conflict. +``"dept"``, but use their own resolver to avoid conflicts. ``has_and_belongs_to_many`` associations do not support polymorphism. From 6589fea989380e537af44fe9dc8d02f216494168 Mon Sep 17 00:00:00 2001 From: Grace Miller Date: Mon, 16 Dec 2024 16:10:29 -0500 Subject: [PATCH 4/5] copy --- source/reference/associations.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/reference/associations.txt b/source/reference/associations.txt index f9981323..81b1279c 100644 --- a/source/reference/associations.txt +++ b/source/reference/associations.txt @@ -1211,7 +1211,7 @@ that a bundle may contain other bundles or products: has_many :items, polymorphic: true end -Starting in version 9.0.2, Mongoid adds support to custom polymorphic types through +Starting in version 9.0.2, Mongoid adds support for custom polymorphic types through a global registry. You can specify alternative keys to represent different classes, thus decoupling the code from the data. The following example specifies the string ``"dept"`` as an alternate key for the ``Department`` class: @@ -1224,14 +1224,14 @@ the string ``"dept"`` as an alternate key for the ``Department`` class: has_many :managers, as: :unit end -The ``identify_as 'dept'`` directive instructs Mongoid to store this class in the -database as the string ``"dept"``. You can also specify multiple aliases. For -example, you can specify the option as: ``identify_as 'dept', 'div', 'agency'``, -in which case the first key is the "default", and the others are used only for -looking up records. This lets you refactor your code without breaking the associations -in your data. +In the preceding example, the ``identify_as 'dept'`` directive instructs Mongoid +to store this class in the database as the string ``"dept"``. You can also specify +multiple aliases. For example, you can specify the option as: +``identify_as 'dept', 'div', 'agency'``, in which case the first key is the "default", +and the others are used only for looking up records. This lets you refactor your +code without breaking the associations in your data. -These aliases are global. The keys you specify must be unique across your +Polymorphic type aliases are global. The keys you specify must be unique across your entire code base. However, it is possible to register alternative resolvers, which must be used for different subsets of your models. In this case, the keys must only be unique for each resolver. The following example shows how to register From 628bdd4a0ccb4f818e270d7ac764afdbca697090 Mon Sep 17 00:00:00 2001 From: Grace Miller Date: Mon, 16 Dec 2024 16:50:14 -0500 Subject: [PATCH 5/5] copy fix --- source/reference/associations.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/reference/associations.txt b/source/reference/associations.txt index 81b1279c..abb6cfd0 100644 --- a/source/reference/associations.txt +++ b/source/reference/associations.txt @@ -1233,7 +1233,7 @@ code without breaking the associations in your data. Polymorphic type aliases are global. The keys you specify must be unique across your entire code base. However, it is possible to register alternative resolvers, which -must be used for different subsets of your models. In this case, the keys must +may be used for different subsets of your models. In this case, the keys must only be unique for each resolver. The following example shows how to register alternate resolvers: