I've this code in my Report model:
has_many :report_reasons, :validate => true has_many :reasons, :through => :report_reasons #, :uniq => true # :accessible => true
def reason_attributes=(reason_attributes) reasons.clear reason_attributes.uniq.each do |reason| reasons << Reason.find_or_create_by_content(reason) end end
What I'm trying to accomplish (and what works) is to have a form which can submit to a Report some Reason via fields_for (Reason :content field). So I just swipe existing associations with .clear and proceed to rebuild new ones. I like to keep things that way so I have my validation errors back, this is true especially when saving a new Report.
What happens here is that, according to rails' code, when the owner object, in this case Report, doesn't exists yet, I can assign to it every kind of Reason I can think of, most importantly even those that doesn't pass validation. Because validations happens at .save I've my errors and I'm quite happy.
However this is different when using update_attributes, for updating. The owner object (Report) already exists, and every invalid Reason assigned through << will simply result in a raised ActiveRecord::InvalidRecord exception. This is best described directly into rails' code in association_collection.rb (<<) and has_many_through_association.rb (insert_record).
Now I may trap this exception in controller and do something with it, however I lose in some way my validation error messages on my form, which is dynamic (add/remove reasons via js).
The reason why I'm not using :accessible or some other plugin to ease multimodel forms is that they wants to create a record in Reason, which is good, but they don't try to reuse it if it already exists. Instead they, of course, will duplicate rows, defeating my purpose.
I can post some other code if anybody have some suggestions on how to proceed.