rails has_many setter 应该设置条件(如果指定)

Posted

技术标签:

【中文标题】rails has_many setter 应该设置条件(如果指定)【英文标题】:rails has_many setter should set conditions if specified 【发布时间】:2011-04-26 04:27:30 【问题描述】:

对我来说,这似乎是 Rails 中的一个错误,但我对此可能无能为力。那么我怎样才能完成我的预期行为呢?

假设我们有:

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 字段已填充。但我也希望看到“真棒”列设置为“真”,但事实并非如此。

此外,如果我从控制台执行以下操作:

>> 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

编辑 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的列)。

【问题讨论】:

【参考方案1】:

你需要使用:

my_user.awesome_friends.create(:name=&gt;'jim')my_user.awesome_friends.build(:name=&gt;'jim')

在文档中: has_many (:conditions)

如果使用散列,则从关联中创建的记录是限定范围的。 has_many :posts, :conditions => :published => true 将使用@blog.posts.create 或@blog.posts.build 创建已发布的帖子。

【讨论】:

不错!我忘了这件事。虽然它不能解决添加/删除现有朋友的问题。不过谢谢,我可能会在我的实现中使用它。 是的。除了设置外键之外,我认为当您将现有对象添加到集合时,它不会修改现有对象。 接受了这个,因为它是我提出的问题的最佳解决方案。但是,请参阅问题中的编辑以了解最终实施。 我会创建 add_to_awesome_friends 和 remove_from_awesome_friends 方法,并通过使用现有的“朋友”对象将逻辑放入其中。【参考方案2】:

一方面是:class_name,而不是:class

【讨论】:

【参考方案3】:

我不认为这不是错误。 :conditions 散列仅确定您如何查询对象。但我认为仅仅假设您在集合中填充的任何对象都可以制作以符合条件是不合理的。

在您的简单示例中,这是有道理的,但您也可以在其中放置更复杂的逻辑。

文档似乎对此也很清楚:

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

:conditions

指定关联对象必须满足的条件才能包含为WHERE SQL 片段,例如authorized = 1

【讨论】:

我同意文档很清楚,这是我检查的第一件事。但在实践中,这对我来说真的没有意义。我想我只需要在添加到集合之前小心地在我的“朋友”对象中设置适当的字段。 在这种情况下,我倾向于创建一个 add_friend 方法来为您执行逻辑。

以上是关于rails has_many setter 应该设置条件(如果指定)的主要内容,如果未能解决你的问题,请参考以下文章

Rails:来自“has_many”的意外 tSYMBEG 错误

Rails 中的 has_many 关联迁移

Rails 4:加入 has_many 关系

Rails:为啥“has_many ...,:通过=> ...”关联导致“NameError:未初始化的常量...”

Ruby-on-Rails:多个 has_many :通过可能吗?

何时在 Rails 中使用“has_many :through”关系?