1

TL;博士

这看起来应该很简单。我想设置#accepts_nested_attributes_for,这样当我使用为子类设置的任何非空参数保存父类时,它会删除在参数中没有被其id直接引用的任何其他子类。

出于某种原因,我真的很难找到一种明智的方式来做到这一点。

就是这样。

更长的版本

我有一个模型,承诺:

class Pledge < ActiveRecord::Base
  has_many :companies, dependent: :destroy
  accepts_nested_attributes_for :companies

  # Other stuff
end

以及相应的公司模型:

class Company < ActiveRecord::Base
  belongs_to :pledge
end

假设我已经将 company_1 (id: 1, name: company_1) 保存在承诺_a 上,然后我调用pledge_.update(params),其中params任何一个都没有引用公司 id,因此:

{  
  "someotherval"=>"5",
  "id"=>"10",
  "companies_attributes"=>
  {  
    "0"=>
    { 
      "name"=>"company_2" 
    }
  }
}

或(与上述完全相同,但是)为相关公司提供不同的 ID:

{  
  "someotherval"=>"5",
  "id"=>"10",
  "companies_attributes"=>
  {  
    "0"=>
    { 
      "id"=>"2"
      "name"=>"company_2" 
    }
  }
}

指示 Rails 删除任何未包含在参数中的公司的最简单方法是什么,即每次我在嵌套参数中使用任何现有公司调用 #update 时创建一个新集合?

我已经尝试了很多东西:

在 Pledge 上使用 before_save 挂钩删除公司 - 这似乎在保存公司删除它们,所以我总是以无公司的承诺结束

通过将 :reject_if 块添加到 accept_nested_attributes_for 一行然后将其用于 destroy_all_companies after_save 挂钩来构建公司数组 - 这不起作用,因为在某些时候 Rails 似乎重新初始化了承诺,所以到那时我们上钩了,数组消失了

在我调用#update 删除公司之前在控制器中编写一些代码 - 这是我已经减少到的黑客,但它是可怕的。首先,如果我传递不包含任何嵌套公司参数的参数,我并不总是想删除公司。其次,我必须检查参数并删除任何非空的公司#id 值,否则 Rails 在找不到相关公司时会爆炸。第三,如果验证失败并且 Pledge 没有更新,我现在已经删除了我不想删除的所有公司。

必须有一个更理智的方法来做到这一点......对吧?

4

1 回答 1

1

给定您要销毁的公司列表,例如:

companies_to_destroy = @pledge.companies.reject do |company|
  pledge_params[:companies_attributes]
    .map { |attrs| attrs[:id] }
    .include? company.id
end

正如@gabrielhilal的评论所建议的那样,您可以使用allow_destroy: trueaccepts_nested_attributes_for然后添加到公司属性数组{ id: 'x', _destroy: '1' }中,以便每个公司销毁。

或者,您可以在要销毁的公司上调用mark_for_destruction 。

在任何一种情况下,当您调用 save 时,要销毁的公司都将被销毁。

于 2020-04-27T13:42:24.887 回答