diff --git a/lib/associations/associations.rb b/lib/associations/associations.rb index 1e14f95..47b0538 100644 --- a/lib/associations/associations.rb +++ b/lib/associations/associations.rb @@ -2,11 +2,35 @@ module ActiveHash module Associations module ActiveRecordExtensions - def self.extended(base) require_relative 'reflection_extensions' end + def has_many(association_id, **options) + if options[:through] + klass_name = association_id.to_s.classify + klass = + begin + klass_name.constantize + rescue StandardError, LoadError + nil + end + + if klass && klass < ActiveHash::Base + define_method(association_id) do + join_models = send(options[:through]) + join_models.flat_map do |join_model| + join_model.send(association_id.to_s.singularize) + end.uniq + end + + return + end + end + + super + end + def belongs_to(name, scope = nil, **options) klass_name = options.key?(:class_name) ? options[:class_name] : name.to_s.camelize klass = @@ -117,6 +141,7 @@ def has_many(association_id, options = {}) klass.where(foreign_key => primary_key_value) end end + define_method("#{association_id.to_s.underscore.singularize}_ids") do public_send(association_id).map(&:id) end @@ -140,7 +165,6 @@ def has_one(association_id, options = {}) end def belongs_to(association_id, options = {}) - options = { :class_name => association_id.to_s.classify, :foreign_key => association_id.to_s.foreign_key, @@ -156,7 +180,6 @@ def belongs_to(association_id, options = {}) define_method("#{association_id}=") do |new_value| attributes[options[:foreign_key].to_sym] = new_value ? new_value.send(options[:primary_key]) : nil end - end end diff --git a/spec/associations/active_record_extensions_spec.rb b/spec/associations/active_record_extensions_spec.rb index f907089..1001df5 100644 --- a/spec/associations/active_record_extensions_spec.rb +++ b/spec/associations/active_record_extensions_spec.rb @@ -48,6 +48,7 @@ def define_school_classes t.integer :locateable_id t.integer :city_id end + extend ActiveHash::Associations::ActiveRecordExtensions end @@ -58,6 +59,45 @@ def define_school_classes define_ephemeral_class(:SchoolStatus, ActiveHash::Base) end + def define_doctor_classes + define_ephemeral_class(:Physician, ActiveHash::Base) do + include ActiveHash::Associations + + has_many :appointments + has_many :patients, through: :appointments + + self.data = [ + {:id => 1, :name => "ikeda"}, + {:id => 2, :name => "sato"} + ] + end + + 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 :patient + end + + extend ActiveHash::Associations::ActiveRecordExtensions + + belongs_to :physician + belongs_to :patient + end + + define_ephemeral_class(:Patient, ActiveRecord::Base) do + establish_connection :adapter => "sqlite3", :database => ":memory:" + connection.create_table :patients, force: true do |t| + end + + extend ActiveHash::Associations::ActiveRecordExtensions + + has_many :appointments + has_many :physicians, through: :appointments + end + + end + before do @ephemeral_classes = [] end @@ -152,6 +192,23 @@ def define_school_classes author.books.to_a end end + + describe ":through" do + before { define_doctor_classes } + + it "finds ActiveHash records through the join model" do + patient = Patient.create! + + physician1 = Physician.first + Appointment.create!(physician: physician1, patient: patient) + Appointment.create!(physician: physician1, patient: patient) + + physician2 = Physician.last + Appointment.create!(physician: physician2, patient: patient) + + expect(patient.physicians).to contain_exactly(physician1, physician2) + end + end end describe ActiveHash::Associations::ActiveRecordExtensions do @@ -332,6 +389,5 @@ def define_school_classes end end end - end end