开发者

Writing to has_many :through associations and callbacks

开发者 https://www.devze.com 2023-02-24 21:33 出处:网络
Consider a \"Name\" model which has a required \"label\" attribute and an arbitrary Rails 3 model \"Foo\" with the following associations:

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消