【问题标题】:Is there a "first_or_build" method on has_many associations?has_many 关联是否有“first_or_build”方法?
【发布时间】:2013-05-27 11:03:05
【问题描述】:

在 rails 3.2+ 中,您可以这样做:

SomeModel.some_scope.first_or_initialize

这意味着你也可以这样做:

OtherModel.some_models.first_or_initialize

我发现这非常有用,但我想在我的 has_many 关联上使用 first_or_build 方法,它的作用类似于 first_or_initialize还向关联添加一条新记录为 @987654326 @ 在需要时执行

澄清更新:是的,我知道first_or_initializefirst_or_create。问题是,first_or_initialize 没有像build 那样将初始化记录添加到关联的目标中,而first_or_create...嗯...创建一条记录,这不是本意。

我有一个可行的解决方案,使用关联扩展:

class OtherModel < ActiveRecord::Base

  has_many :some_models do 
    def first_or_build( attributes = {}, options = {}, &block )
      object = first_or_initialize( attributes, options, &block )
      proxy_association.add_to_target( object ) if object.new_record?
      object
    end
  end

end

我只是想知道:

  • 这个问题的内置解决方案已经存在?
  • 我的实现有我看不到的缺陷?

【问题讨论】:

  • 如果你想在某个时候在OtherModel.some_models 上执行急切的加载程序怎么办?我宁愿在after_initialize 回调中执行这样的初始化,它更干净的方法 IMO。

标签: ruby-on-rails activerecord associations


【解决方案1】:

我不确定 Rails 中是否有任何内置功能可以完全满足您的需求,但您可以使用比您当前使用的更简洁的扩展来模仿 first_or_initialize 代码,我相信它可以满足您的需求,并且将其包装成一个可重用的扩展,如下所示。这是用 Rails 3.2 扩展格式编写的。

module FirstOrBuild
  def first_or_build(attributes = nil, options = {}, &block)
    first || build(attributes, options, &block)
  end
end

class OtherModel < ActiveRecord::Base
  has_many :some_models, :extend => FirstOrBuild
end

【讨论】:

  • 完全正确。我不知道为什么我这样过度设计,这显然更好。
  • 为了让它在 Rails 4.1.0.beta 中工作,我必须在范围上下文中指定代理关联;这样扩展读取first || scoping{ proxy_association.build(attributes, &amp;block) }(在任何地方都没有选项)并且调用看起来像Post.first.comments.where(foo: 'bar').first_or_build。我还在 Post 上使用了新语法 has_many :posts, -> { extended FirstOrBuild }。)
  • @ChrisKeele 感谢您的更新。当您执行 foo.bars.where(title: 'buzz').first_or_build 之类的操作时,这是否仍能按预期工作? (即,一个新栏被添加到 foo.bars,它的标题为 'buzz')。作为旁注,我刚刚注意到 first_or_create 也没有将记录添加到 proxy_association 的目标中。也许我应该向 Rails 团队提交一张票,API 的当前状态不遵循最小惊喜原则恕我直言
  • foo.bars.where(title: 'buzz').first_or_build(desc: 'baz') 仍然通过title 查找(如果存在),使用预期的titledesc 构建记录(如果不存在),并将bar 添加到foo 的集合中其中。
  • 我使用的是 Rails 3.2.17,我不得不使用 @ChrisKeele 的代码(它就像一个魅力)。请注意阅读本文的其他人——接受的答案不适用于某些版本的 Rails 3.2。
猜你喜欢
  • 1970-01-01
  • 2015-03-17
  • 2021-08-14
  • 2016-12-04
  • 2012-05-30
  • 1970-01-01
  • 2011-02-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多