【问题标题】:Different behavior of build method构建方法的不同行为
【发布时间】:2015-05-27 16:21:47
【问题描述】:

我试图实现first_or_build 方法,但在保存我的父母时遇到了一个问题:孩子们失踪了。

当我在 parent.childs.first_or_build(name: 'Foo'); parent.save! 这样的关系上调用我的方法时,一切正常,而当我调用 parent.childs.where(name: 'Foo').first_or_build; parent.save! 时没有任何反应。

主要目标是提出与.first_or_create 类似的行为,例如应用于查询结果。 (不要告诉我.first_or_initialize!)

有什么想法吗?

例子:

# this is not working :(
2.times { |i| parent.childs.where(name: "child #{i}").build { |c| c.age = 42 } } ; parent.childs  
=> #<ActiveRecord::Associations::CollectionProxy []>

# while this is
2.times { |i| parent.childs.build { |c| c.name = "#{child #{i}"; c.age = 42 } } ; parent.childs  
=> #<ActiveRecord::Associations::CollectionProxy [#<Child name: "child 0", age: 42>, #<Child name: "child 1", age: 42>]>

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 activerecord associations


    【解决方案1】:

    对不起,关于 first_or_build 方法的部分我没有完全理解,所以我只讲那里的例子。

    首先,我们知道 parent.childs.where(name: "child #{i}") 和 parent.childs 属于不同的类

        parent.children.where(name: "child").class
        #=>  Child::ActiveRecord_AssociationRelation
    
        parent.children.class
        #=>  Child::ActiveRecord_Associations_CollectionProxy
    

    所以很清楚为什么他们的 :build 方法不同,文档在这里

    ActiveRecord_Associations_CollectionProxy

    ActiveRecord_AssociationRelation

    我将尝试在这里表达我的观点。 当你使用 ActiveRecord_AssociationRelation 建立一个新的 child 时,它会初始化一个新的 Child 对象,并设置它的 parent_id,但它只是一个 Child 对象。这时候执行parent.children,结果是空的。

    parent.children.where(name: "child1").build({age: 1})
    #=> <Child id: nil, name: "child1", age: 1, parent_id: 1, created_at: nil, updated_at: nil>
    parent.children
    #=> <ActiveRecord::Associations::CollectionProxy []>
    parent.save #=> true
    parent.children.reload
    #=> <ActiveRecord::Associations::CollectionProxy []>
    

    但是当你使用ActiveRecord_Associations_CollectionProxy时,它会初始化一个新的Child对象,同时它也会将自己附加到parent,所以当你执行parent.children时,结果不为空。

    parent.children.build({name: "child2", age: 2})
    #=> <Child id: nil, name: "child2", age: 2, parent_id: 1, created_at: nil, updated_at: nil
    parent.children
    #=>  <ActiveRecord::Associations::CollectionProxy [#<Child id: nil, name: "child2", age: 2, parent_id: 1, created_at: nil, updated_at: nil>]>
    parent.save #=> true
    parent.children.reload
    #=> <ActiveRecord::Associations::CollectionProxy [#<Child id: 3, name: "child2", age: 2, parent_id: 1, created_at: "2015-05-28 17:02:39", updated_at: "2015-05-28 17:02:39">]>
    

    第二种方式,父母知道它有孩子,所以当它保​​存时,它会保存它的孩子。我想就是这样。

    【讨论】:

    • 这个例子当然有两个类。我不明白为什么,虽然这两种方法都实例化了新的Child 对象,但只有第一种方法在保存parent 时才允许保存新的children。在这两种情况下,当打印新子代时,您可以看到它们包含其父代的 id。
    • 它们都只是新的 Child 对象,即使它们包含其父对象的 id,它们还没有被写入数据库。但是第二种方式,父对象会知道它有子对象,所以当父对象保存时,它会同时保存它的子对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 2011-03-16
    • 2019-04-08
    • 2020-01-23
    • 2012-04-09
    • 1970-01-01
    相关资源
    最近更新 更多