From f4bc19c5246c8fb2b1d212d19501e61e8b9d3db9 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Wed, 13 Aug 2025 17:27:43 -0400 Subject: [PATCH 1/2] Silence spec duplicate const warnings We undefine these classes in the after {} So in theory, they should not be a duplicate. rspec often uses stub_const, but active record has issues with this since they dig into the class.name and stuff --- spec/associations/active_record_extensions_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/associations/active_record_extensions_spec.rb b/spec/associations/active_record_extensions_spec.rb index 50b6fb9..e5a95e1 100644 --- a/spec/associations/active_record_extensions_spec.rb +++ b/spec/associations/active_record_extensions_spec.rb @@ -5,7 +5,7 @@ def define_ephemeral_class(name, superclass, &block) klass = Class.new(superclass) - Object.const_set(name, klass) + Kernel::silence_warnings { Object.const_set(name, klass) } klass.class_eval(&block) if block_given? @ephemeral_classes << name end From fd528211d00b10eec24a76b9c0d030bea9450d15 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Mon, 18 Aug 2025 12:44:35 -0400 Subject: [PATCH 2/2] Handle belongs_to :through, :polymorphic: true --- lib/associations/associations.rb | 8 ++++++-- .../active_record_extensions_spec.rb | 16 ++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/associations/associations.rb b/lib/associations/associations.rb index 3ffd77d..a9221d1 100644 --- a/lib/associations/associations.rb +++ b/lib/associations/associations.rb @@ -10,8 +10,12 @@ def has_many(association_id, scope = nil, **options, &extension) if options[:through] source_association_name = options[:source]&.to_s || association_id.to_s.singularize - through_klass = reflect_on_association(options[:through])&.klass - klass = through_klass&.reflect_on_association(source_association_name)&.klass + klass = if options[:source_type] + options[:source_type].safe_constantize + else + through_klass = reflect_on_association(options[:through])&.klass + through_klass&.reflect_on_association(source_association_name)&.klass + end if klass && klass < ActiveHash::Base define_method(association_id) do diff --git a/spec/associations/active_record_extensions_spec.rb b/spec/associations/active_record_extensions_spec.rb index e5a95e1..3979615 100644 --- a/spec/associations/active_record_extensions_spec.rb +++ b/spec/associations/active_record_extensions_spec.rb @@ -101,13 +101,14 @@ def define_doctor_classes define_ephemeral_class(:Appointment, ActiveRecord::Base) do establish_connection :adapter => "sqlite3", :database => ":memory:" connection.create_table :appointments, force: true do |t| - t.references :physician + t.references :providerable, polymorphic: true t.references :patient end extend ActiveHash::Associations::ActiveRecordExtensions - belongs_to :physician + belongs_to :providerable, polymorphic: true + belongs_to :physician, -> { where(:providerable_type => "Physician")}, :foreign_key => :providerable_id belongs_to :patient end @@ -119,9 +120,8 @@ def define_doctor_classes extend ActiveHash::Associations::ActiveRecordExtensions has_many :appointments - has_many :physicians, through: :appointments + has_many :physicians, through: :appointments, source: :providerable, source_type: "Physician" end - end before do @@ -226,11 +226,11 @@ def define_doctor_classes patient = Patient.create! physician1 = Physician.first - Appointment.create!(physician: physician1, patient: patient) - Appointment.create!(physician: physician1, patient: patient) + Appointment.create!(providerable: physician1, patient: patient) + Appointment.create!(providerable: physician1, patient: patient) physician2 = Physician.last - Appointment.create!(physician: physician2, patient: patient) + Appointment.create!(providerable: physician2, patient: patient) expect(patient.physicians).to contain_exactly(physician1, physician2) end @@ -264,7 +264,7 @@ def define_doctor_classes define_method(:physician) { raise NoMethodError, "The #physician association is removed in this spec, use #doctor" } define_method(:physician=) { |_| raise NoMethodError, "The #physician association is removed in this spec, use #doctor" } end - Appointment.belongs_to :doctor, class_name: 'Physician', foreign_key: :physician_id + Appointment.belongs_to :doctor, class_name: 'Physician', foreign_key: :providerable_id # NOTE: Removing the Patient#physicians association and adding Patient#doctors Patient._reflections.delete('physicians')