对我来说,这似乎是Rails中的一个bug,但我可能对此无能为力。那么我怎样才能实现我的预期行为呢?
假设有:
class User < ActiveRecord::Base
has_many :awesome_friends, :class_name => "Friend", :conditions => {:awesome => true}
end
并执行代码:
>> my_user.awesome_friends << Friend.new(:name=>'jim')
之后,当我检查这个好友对象时,我看到user_id字段被填充。但我也希望看到"awesome"一栏设置为"true",但事实并非如此。
此外,如果我从控制台中执行以下命令:
>> 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
= []
对此有什么想法吗?我假设条件哈希值可以任意复杂,不可能集成到setter中。但在某种程度上,感觉默认情况下我们正在传递条件":user_id => self"。Id",这是固定的,那么其他人不应该这样做吗?
谢谢,迈克
编辑:我发现has_many有回调函数,所以我想我可以这样定义它们之间的关系:
has_many :awesome_friends,
:class_name => "Friend",
:conditions => {:awesome => true},
:before_add => Proc.new{|p,c| c.awesome = true},
:before_remove => Proc.new{|p,c| c.awesome = false}
虽然,它开始感觉可能我只是实现一些其他的,现有的设计模式。也许我应该子类AwesomeFriend <的朋友吗?最终,我需要几个这样的has_many关系,而子类会因为所有额外的文件而变得混乱。>
编辑2:
好的,感谢所有评论的人!我最终将上面的方法包装成一个漂亮的小ActiveRecord扩展,'has_many_of_type'。其工作方式如下:
has_many_of_type :awesome_friends, :class_name => "Friend", :type=>:awesome
转换成带有适当条件的has_many,即before_add和before_remove参数(并且它假定存在一个名为friend_type的列)。
你需要使用:
my_user.awesome_friends.create(:name=>'jim')
或my_user.awesome_friends.build(:name=>'jim')
has_many(条件)
如果使用散列,则关联中的记录创建是有范围的。Has_many:posts,:conditions => {:published => true}将使用@blog.posts创建已发布的帖子。创建或创建@blog.posts.build.
首先是:class_name
而不是:class
。
我认为这不是一个bug。条件散列仅决定如何查询对象。但我认为,仅仅假设你在集合中放入的任何对象都可以制作以符合条件是不合理的。
在你的简单示例中,它是有意义的,但你也可以在那里放入更复杂的逻辑。
文档对这一点似乎也很清楚:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
:conditions
指定关联对象必须满足的条件,以便作为
WHERE
SQL片段包含,例如authorized = 1
。