@@ -164,43 +164,63 @@ def push_onto_collection(model, association, ar_instance)
164164 @attributes [ association . attribute ] << ar_instance
165165 end
166166
167+ # class Membership < ActiveRecord::Base
168+ # belongs_to :uzer
169+ # belongs_to :memerable, polymorphic: true
170+ # end
171+ #
172+ # class Project < ActiveRecord::Base
173+ # has_many :memberships, as: :memerable, dependent: :destroy
174+ # has_many :uzers, through: :memberships
175+ # end
176+ #
177+ # class Group < ActiveRecord::Base
178+ # has_many :memberships, as: :memerable, dependent: :destroy
179+ # has_many :uzers, through: :memberships
180+ # end
181+ #
182+ # class Uzer < ActiveRecord::Base
183+ # has_many :memberships
184+ # has_many :groups, through: :memberships, source: :memerable, source_type: 'Group'
185+ # has_many :projects, through: :memberships, source: :memerable, source_type: 'Project'
186+ # end
187+
188+ # membership.uzer = some_new_uzer (i.e. through association is changing)
189+ # means membership.some_new_uzer.(groups OR projects) << uzer.memberable (depending on type of memberable)
190+ # and we have to remove the current value of the source association (memerable) from the current uzer group or project
191+ # and we have to then find any inverse has_many_through association (i.e. group or projects.uzers) and delete the
192+ # current value from those collections and push the new value on
193+
167194 def update_has_many_through_associations ( assoc , value )
168195 # note that through and source_associations returns an empty set of
169196 # the provided ar_instance does not belong to a has_many_through association
170- assoc . through_associations ( value )
171- . each { |ta | update_through_association ( assoc , ta , value ) }
172- assoc . source_associations ( value )
173- . each { |sa | update_source_association ( assoc , sa , value ) }
174- end
175-
176- def update_through_association ( assoc , ta , new_belongs_to_value )
177- # appointment.doctor = doctor_new_value (i.e. through association is changing)
178- # means appointment.doctor_new_value.patients << appointment.patient
179- # and we have to appointment.doctor_current_value.patients.delete(appointment.patient)
180- source_value = @attributes [ ta . source ]
181- current_belongs_to_value = @attributes [ assoc . attribute ]
182- return unless source_value . class . to_s == ta . source_type
183- unless current_belongs_to_value . nil? || current_belongs_to_value . attributes [ ta . attribute ] . nil?
184- current_belongs_to_value . attributes [ ta . attribute ] . delete ( source_value )
197+ assoc . through_associations ( value ) . each do |ta |
198+ source_value = @attributes [ ta . source ]
199+ current_value = @attributes [ assoc . attribute ]
200+ # skip if source value is nil or if type of the association does not match type of source
201+ next unless source_value . class . to_s == ta . source_type
202+ update_through_association ( ta , source_value , current_value , value )
203+ ta . source_associations ( source_value ) . each do |sa |
204+ update_source_association ( sa , source_value , current_value , value )
205+ end
185206 end
186- return unless new_belongs_to_value
187- new_belongs_to_value . attributes [ ta . attribute ] ||= Collection . new ( assoc . owner_class , new_belongs_to_value , ta )
188- new_belongs_to_value . attributes [ ta . attribute ] << source_value
189- end
190-
191- def update_source_association ( assoc , sa , new_source_value )
192- # appointment.patient = patient_value (i.e. source is changing)
193- # means appointment.doctor.patients.delete(appointment.patient)
194- # means appointment.doctor.patients << patient_value
195- belongs_to_value = @attributes [ assoc . attribute ]
196- current_source_value = @attributes [ sa . source ]
197- return unless belongs_to_value
198- unless belongs_to_value . attributes [ sa . attribute ] . nil? || current_source_value . nil?
199- belongs_to_value . attributes [ sa . attribute ] . delete ( current_source_value )
207+ end
208+
209+ def update_through_association ( ta , source_value , current_value , new_value )
210+ unless current_value . nil? || current_value . attributes [ ta . attribute ] . nil?
211+ current_value . attributes [ ta . attribute ] . delete ( source_value )
200212 end
201- return unless new_source_value
202- belongs_to_value . attributes [ sa . attribute ] ||= Collection . new ( sa . klass ( new_source_value ) , belongs_to_value , sa )
203- belongs_to_value . attributes [ sa . attribute ] << new_source_value
213+ return unless new_value
214+ new_value . attributes [ ta . attribute ] ||= Collection . new ( ta . owner_class , new_value , ta )
215+ new_value . attributes [ ta . attribute ] << source_value
216+ end
217+
218+ def update_source_association ( sa , source_value , current_value , new_value )
219+ source_inverse_collection = source_value . attributes [ sa . attribute ]
220+ source_inverse_collection . delete ( current_value ) if source_inverse_collection
221+ return unless new_value
222+ source_value . attributes [ sa . attribute ] ||= Collection . new ( sa . owner_class , source_value , sa )
223+ source_value . attributes [ sa . attribute ] << new_value
204224 end
205225 end
206226end
0 commit comments