rails has_many setter should set conditions if specified
This seems like a bug in Rails to me, but there's probably not much I can do about that. So how can I accomplish my expected behavior?
Suppose we have:
class User < ActiveRecord::Base
has_many :awesome_friends, :class_name => "Friend", :conditions => {:awesome => true}
end
And execute the code:
>> my_user.awesome_friends << Friend.new(:name=>'jim')
Afterwards, when I inspect this friend object, I see that the user_id field is populated. But I would also expect to see the "awesome" column set to 'true', which it is not.
Furthermore, if I execute the following from the console:
>> my_user.awesome_friends << Friend.new(:name=>'jim')
>> my_user.awesome_friends
= [#<Friend id:1, name:"jim", awesome:nil>]
# Quit and restart the console
>> my_user.awesome_friends
= []
Any thoughts on this? I suppose the conditions hash could be arbitrarily complex, making integration into the setter impossible. But in a way it feels like by default we are passing the condition ":user_id => self.id", and that gets set, so shouldn't others?
Thanks, Mike
EDIT:
I found that there are callbacks for has_many, so I think I might define the relationship like this:
has_many :awesome_friends,
:class_name => "Friend",
:conditions =&g开发者_JS百科t; {:awesome => true},
:before_add => Proc.new{|p,c| c.awesome = true},
:before_remove => Proc.new{|p,c| c.awesome = false}
Although, it's starting to feel like maybe I'm just implementing some other, existing design pattern. Maybe I should subclass AwesomeFriend < Friend? Ultimately I need a couple of these has_many relationships, and subclassing get's messy with all the extra files..
EDIT 2:
Okay, thanks to everyone who commented! I ultimately wrapped up the method above into a nice little ActiveRecord extension, 'has_many_of_type'. Which works like follows:
has_many_of_type :awesome_friends, :class_name => "Friend", :type=>:awesome
Which just translates to has_many with the appropriate conditions, before_add, and before_remove params (and it assumes the existence of a column named friend_type).
You need use:
my_user.awesome_friends.create(:name=>'jim')
or my_user.awesome_friends.build(:name=>'jim')
In documentation: has_many (:conditions)
Record creations from the association are scoped if a hash is used. has_many :posts, :conditions => {:published => true} will create published posts with @blog.posts.create or @blog.posts.build.
It's :class_name
rather than :class
, for one thing.
This isn't a bug I don't think. The :conditions hash only deterimines how you query for the objects. But I don't think it's rational to just assume that any object you stuff in the collection could be made to conform to the conditions.
In your simple example it makes sense, but you could also put more complex logic in there.
The documentation seems pretty clear on this as well:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
:conditions
Specify the conditions that the associated object must meet in order to be included as a
WHERE
SQL fragment, such asauthorized = 1
.
精彩评论