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 50b6fb9..3979615 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 @@ -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')