From f77fc1ef9810788803e6d9d23d2f6fd40fb8dd90 Mon Sep 17 00:00:00 2001 From: Wendy Chen Date: Tue, 12 Dec 2023 14:16:02 -0500 Subject: [PATCH 1/2] write attribute with polymorphic integer type --- lib/polymorphic_integer_type.rb | 1 + lib/polymorphic_integer_type/extensions.rb | 29 +++++++++++++++++-- ...lymorphic_foreign_association_extension.rb | 13 +++++++++ spec/polymorphic_integer_type_spec.rb | 26 +++++++++++++++++ spec/support/animal.rb | 2 +- 5 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 lib/polymorphic_integer_type/polymorphic_foreign_association_extension.rb diff --git a/lib/polymorphic_integer_type.rb b/lib/polymorphic_integer_type.rb index a68099c..b5bf33d 100644 --- a/lib/polymorphic_integer_type.rb +++ b/lib/polymorphic_integer_type.rb @@ -6,6 +6,7 @@ require "polymorphic_integer_type/module_generator" require "polymorphic_integer_type/belongs_to_polymorphic_association_extension" require "polymorphic_integer_type/activerecord_5_0_0/polymorphic_array_value_extension" +require "polymorphic_integer_type/polymorphic_foreign_association_extension" if ACTIVE_RECORD_VERSION < Gem::Version.new("5.2.0") require "polymorphic_integer_type/activerecord_5_0_0/association_query_handler_extension" diff --git a/lib/polymorphic_integer_type/extensions.rb b/lib/polymorphic_integer_type/extensions.rb index 9d43529..64f3999 100644 --- a/lib/polymorphic_integer_type/extensions.rb +++ b/lib/polymorphic_integer_type/extensions.rb @@ -58,6 +58,8 @@ def remove_type_and_establish_mapping(name, options, scope) options[:foreign_key] ||= "#{poly_type}_id" foreign_type = options.delete(:foreign_type) || "#{poly_type}_type" + options[:foreign_integer_type] = foreign_type + options[:integer_type] = klass_mapping.to_i options[:scope] ||= -> { condition = where(foreign_type => klass_mapping.to_i) @@ -87,7 +89,9 @@ def has_many(name, scope = nil, **options, &extension) end remove_type_and_establish_mapping(name, options, scope) - super(name, options.delete(:scope), **options, &extension) + super(name, options.delete(:scope), **options.except(:foreign_integer_type, :integer_type), &extension).tap do |_| + remove_integer_type_and_set_attributes_and_extension(options, ActiveRecord::Reflection::HasManyReflection, reflections[name.to_s]) + end end def has_one(name, scope = nil, **options) @@ -97,7 +101,28 @@ def has_one(name, scope = nil, **options) end remove_type_and_establish_mapping(name, options, scope) - super(name, options.delete(:scope), **options) + super(name, options.delete(:scope), **options.except(:foreign_integer_type, :integer_type)).tap do |_| + remove_integer_type_and_set_attributes_and_extension(options, ActiveRecord::Reflection::HasOneReflection, reflections[name.to_s]) + end + end + + def remove_integer_type_and_set_attributes_and_extension(options, klass, reflection) + foreign_integer_type = options.delete :foreign_integer_type + integer_type = options.delete :integer_type + is_polymorphic_integer = foreign_integer_type && integer_type + + if is_polymorphic_integer + klass.attr_accessor(:foreign_integer_type) + klass.attr_accessor(:integer_type) + reflection.foreign_integer_type = foreign_integer_type + reflection.integer_type = integer_type + + if Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("6.1") + ActiveRecord::Associations::Association.prepend(ActiveRecord::Associations::PolymorphicForeignAssociationExtension) + else + ActiveRecord::Associations::ForeignAssociation.prepend(ActiveRecord::Associations::PolymorphicForeignAssociationExtension) + end + end end diff --git a/lib/polymorphic_integer_type/polymorphic_foreign_association_extension.rb b/lib/polymorphic_integer_type/polymorphic_foreign_association_extension.rb new file mode 100644 index 0000000..18610f7 --- /dev/null +++ b/lib/polymorphic_integer_type/polymorphic_foreign_association_extension.rb @@ -0,0 +1,13 @@ +module ActiveRecord + module Associations + module PolymorphicForeignAssociationExtension + + def set_owner_attributes(record) + super + if reflection.foreign_integer_type && reflection.integer_type + record._write_attribute(reflection.foreign_integer_type, reflection.integer_type) + end + end + end + end +end diff --git a/spec/polymorphic_integer_type_spec.rb b/spec/polymorphic_integer_type_spec.rb index 563fa49..c12f8d0 100644 --- a/spec/polymorphic_integer_type_spec.rb +++ b/spec/polymorphic_integer_type_spec.rb @@ -26,6 +26,28 @@ expect(link.target_type).to eq("Food") end + context "from HasManyReflection" do + it "sets the source properly from HasManyReflection" do + link_1 = Link.create() + link_2 = Link.create() + dog.source_links = [link_1, link_2] + expect(link_1.source_type).to eq("Animal") + expect(link_1.source_id).to eq(dog.id) + expect(link_2.source_type).to eq("Animal") + expect(link_1.source_id).to eq(dog.id) + end + end + + context "from HasOneReflection" do + it "sets the source properly from HasManyReflection" do + link = Link.create() + dog.source_link = link + + expect(link.source_type).to eq("Animal") + expect(link.source_id).to eq(dog.id) + end + end + context "when models are namespaced" do context "and mappings include namespaces" do it "sets the source_type" do @@ -340,6 +362,10 @@ class InlineDrink2 < ActiveRecord::Base expect(link[:target_type]).to eq(13) end + it "pulls mapping from given hash" do + animal.source_links.new + end + it "doesn't break string type polymorphic associations" do expect(link.normal_target).to eq(drink) expect(link.normal_target_type).to eq("InlineDrink2") diff --git a/spec/support/animal.rb b/spec/support/animal.rb index ca7db21..3a83839 100644 --- a/spec/support/animal.rb +++ b/spec/support/animal.rb @@ -3,5 +3,5 @@ class Animal < ActiveRecord::Base belongs_to :owner, class_name: "Person" has_many :source_links, as: :source, integer_type: true, class_name: "Link" - + has_one :source_link, as: :source, integer_type: true, class_name: "Link" end \ No newline at end of file From 2164bf3e7bb286a738f998a9beb65d6617ec923d Mon Sep 17 00:00:00 2001 From: Wendy Chen Date: Wed, 13 Dec 2023 10:52:47 -0500 Subject: [PATCH 2/2] comments' refactor --- .gitignore | 1 + CHANGELOG.md | 13 ++++++++ lib/polymorphic_integer_type/extensions.rb | 32 ++++++++++--------- ...lymorphic_foreign_association_extension.rb | 14 ++++---- lib/polymorphic_integer_type/version.rb | 2 +- spec/polymorphic_integer_type_spec.rb | 4 +-- 6 files changed, 40 insertions(+), 26 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.gitignore b/.gitignore index 35bf47d..1abc64e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ tmp .byebug_history polymorphic_integer_type_test gemfiles/*.lock +.idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e7cb58e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +### Changed + +## v3.2.1 (2023-12-14) + +### Fixed + +- Not proper assigning polymorphic value with `has_many` and `has_one` reflection. + +### Added + +- Added .idea/ folder to .gitignore + +### Changed \ No newline at end of file diff --git a/lib/polymorphic_integer_type/extensions.rb b/lib/polymorphic_integer_type/extensions.rb index 64f3999..c6c1389 100644 --- a/lib/polymorphic_integer_type/extensions.rb +++ b/lib/polymorphic_integer_type/extensions.rb @@ -2,6 +2,10 @@ module PolymorphicIntegerType module Extensions module ClassMethods + ActiveRecord::Reflection::HasManyReflection.attr_accessor(:foreign_integer_type) + ActiveRecord::Reflection::HasManyReflection.attr_accessor(:integer_type) + ActiveRecord::Reflection::HasOneReflection.attr_accessor(:foreign_integer_type) + ActiveRecord::Reflection::HasOneReflection.attr_accessor(:integer_type) def belongs_to(name, scope = nil, **options) options = scope if scope.kind_of? Hash @@ -58,16 +62,16 @@ def remove_type_and_establish_mapping(name, options, scope) options[:foreign_key] ||= "#{poly_type}_id" foreign_type = options.delete(:foreign_type) || "#{poly_type}_type" - options[:foreign_integer_type] = foreign_type - options[:integer_type] = klass_mapping.to_i options[:scope] ||= -> { condition = where(foreign_type => klass_mapping.to_i) condition = instance_exec(&scope).merge(condition) if scope.is_a?(Proc) condition } + return foreign_type, klass_mapping.to_i else options[:scope] ||= scope + return nil, nil end end @@ -88,9 +92,9 @@ def has_many(name, scope = nil, **options, &extension) scope = nil end - remove_type_and_establish_mapping(name, options, scope) - super(name, options.delete(:scope), **options.except(:foreign_integer_type, :integer_type), &extension).tap do |_| - remove_integer_type_and_set_attributes_and_extension(options, ActiveRecord::Reflection::HasManyReflection, reflections[name.to_s]) + integer_type_values = remove_type_and_establish_mapping(name, options, scope) + super(name, options.delete(:scope), **options, &extension).tap do + remove_integer_type_and_set_attributes_and_extension(integer_type_values, reflections[name.to_s]) end end @@ -100,27 +104,25 @@ def has_one(name, scope = nil, **options) scope = nil end - remove_type_and_establish_mapping(name, options, scope) - super(name, options.delete(:scope), **options.except(:foreign_integer_type, :integer_type)).tap do |_| - remove_integer_type_and_set_attributes_and_extension(options, ActiveRecord::Reflection::HasOneReflection, reflections[name.to_s]) + integer_type_values = remove_type_and_establish_mapping(name, options, scope) + super(name, options.delete(:scope), **options).tap do + remove_integer_type_and_set_attributes_and_extension(integer_type_values, reflections[name.to_s]) end end - def remove_integer_type_and_set_attributes_and_extension(options, klass, reflection) - foreign_integer_type = options.delete :foreign_integer_type - integer_type = options.delete :integer_type + def remove_integer_type_and_set_attributes_and_extension(integer_type_values, reflection) + foreign_integer_type = integer_type_values[0] + integer_type = integer_type_values[1] is_polymorphic_integer = foreign_integer_type && integer_type if is_polymorphic_integer - klass.attr_accessor(:foreign_integer_type) - klass.attr_accessor(:integer_type) reflection.foreign_integer_type = foreign_integer_type reflection.integer_type = integer_type if Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("6.1") - ActiveRecord::Associations::Association.prepend(ActiveRecord::Associations::PolymorphicForeignAssociationExtension) + ActiveRecord::Associations::Association.prepend(PolymorphicIntegerType::PolymorphicForeignAssociationExtension) else - ActiveRecord::Associations::ForeignAssociation.prepend(ActiveRecord::Associations::PolymorphicForeignAssociationExtension) + ActiveRecord::Associations::ForeignAssociation.prepend(PolymorphicIntegerType::PolymorphicForeignAssociationExtension) end end end diff --git a/lib/polymorphic_integer_type/polymorphic_foreign_association_extension.rb b/lib/polymorphic_integer_type/polymorphic_foreign_association_extension.rb index 18610f7..2b18d05 100644 --- a/lib/polymorphic_integer_type/polymorphic_foreign_association_extension.rb +++ b/lib/polymorphic_integer_type/polymorphic_foreign_association_extension.rb @@ -1,12 +1,10 @@ -module ActiveRecord - module Associations - module PolymorphicForeignAssociationExtension +module PolymorphicIntegerType + module PolymorphicForeignAssociationExtension - def set_owner_attributes(record) - super - if reflection.foreign_integer_type && reflection.integer_type - record._write_attribute(reflection.foreign_integer_type, reflection.integer_type) - end + def set_owner_attributes(record) + super + if reflection.foreign_integer_type && reflection.integer_type + record._write_attribute(reflection.foreign_integer_type, reflection.integer_type) end end end diff --git a/lib/polymorphic_integer_type/version.rb b/lib/polymorphic_integer_type/version.rb index 7bd53b6..28ec6e3 100644 --- a/lib/polymorphic_integer_type/version.rb +++ b/lib/polymorphic_integer_type/version.rb @@ -1,3 +1,3 @@ module PolymorphicIntegerType - VERSION = "3.2.0" + VERSION = "3.2.1" end diff --git a/spec/polymorphic_integer_type_spec.rb b/spec/polymorphic_integer_type_spec.rb index c12f8d0..3d56eb2 100644 --- a/spec/polymorphic_integer_type_spec.rb +++ b/spec/polymorphic_integer_type_spec.rb @@ -27,7 +27,7 @@ end context "from HasManyReflection" do - it "sets the source properly from HasManyReflection" do + it "sets the source properly HasManyReflection" do link_1 = Link.create() link_2 = Link.create() dog.source_links = [link_1, link_2] @@ -39,7 +39,7 @@ end context "from HasOneReflection" do - it "sets the source properly from HasManyReflection" do + it "sets the source properly HasOneReflection" do link = Link.create() dog.source_link = link