Writing to has_many :through associations and callbacks
Consider a "Name" model which has a required "label" attribute and an arbitrary Rails 3 model "Foo" with the following associations:
has_many :names, :dependent => :destroy
has_many :special_names, :through => :names, :source => :label, :conditions => { 'special_names.label' => 'special' }, :dependent => :destroy
Now it's possible to access the "special_names" attribute for reading the association, but writing to it fails because AR cannot infer from the condition that the "label" attribute needs to be set to "special" for all members of the "special names" association.
I attempted to use the "add_before" association callback, but that never gets called with the join model (instead the ":source" and "Foo" are used).
Any ideas on how to handle this in the model (as opposed to: using special logic in th开发者_StackOverflow社区e controller to deal with this - that's how I handle it currently)?
Edit: (regarding the answer from Ray Baxter)
The relationship expressed is actually a "has_many :through" association. I'll try again, this time with a (hopefully) better example:
# Label is a shared entity which is used in many contexts
has_many :labels, :through => :user_labels
# UserLabel is the join model which qualifies the usage of a Label
has_many :user_labels, :dependent => :destroy
# special_user_labels is the topic of this question
has_many :special_user_labels, :through => :user_labels, :source => :label, :conditions => { 'user_labels.descriptor' => 'special' }, :dependent => :destroy
If my comment above is correct, and you aren't doing a has_many :through
, this works:
has_many :special_names, :class_name => 'Name', :conditions => {:label => 'special'}, :dependent => :destroy
so now you can do
foo = Foo.create
foo.special_name.build
and ActiveRecord
will correctly instantiate your special_name with the label
attribute having the value "special"
.
I found the solution (thanks x0f@Freenode) - one needs to split the 'special' associations in two. has_many :special_user_labels, :through => :user_labels, :source => :label, :conditions => { 'user_labels.descriptor' => 'special' }, :dependent => :destroy
becomes
1) has_many :special_labels, :class_name => 'UserLabel', :conditions => { :descriptor => 'special' }, :dependent => :destroy
2) has_many :special_user_labels, :through => :special_labels, :source => :label, :dependent => :destroy
Works for reading & writing as well as a seamless replacement for (scoped) hbtm associations.
精彩评论