Rails将accepts_nested_attributes_for与Emirates_to一起使用。为什么我不能设置身份证?

时间:2018-11-29 10:39:01

标签: ruby-on-rails activerecord ruby-on-rails-5

我使用Rails 5.1.6并在accepts_nested_attributes_for上遇到麻烦。

我有两个模型

class Material < ApplicationRecord
  belongs_to :rubric, optional: true
  accepts_nested_attributes_for :rubric
end

class Rubric < ApplicationRecord
  has_many :materials, dependent: :nullify
end

我尝试通过rubric_attributes设置新的项目ID。

describe 'create material' do
  it 'should set rubric: :id' do
    # prepare
    item = FactoryBot.build(:material)
    rubric = FactoryBot.create(:rubric)

    # action
    item.assign_attributes(
      rubric_attributes: {
        id: rubric.id
      }
    )

    # check
    expect(item.valid?).to eq(true)
    expect(item.save).to eq(true)
    expect(item.rubric_id).to eq(rubric.id)
  end
end

但是我有一个错误:

 Failure/Error:
   item.assign_attributes(
     rubric_attributes: {
       id: rubric.id
     }
   )

 ActiveRecord::RecordNotFound:
   Couldn't find Rubric with ID=1 for Material with ID=1

我在更新资料时也遇到同样的错误。

accepts_nested_attributes_for是否是可预测的行为,并且我不能使用rubric_attributes设置现有的rubric ID?

3 个答案:

答案 0 :(得分:1)

Docs说:

  

对于每个没有id键的哈希,除非该哈希还包含一个评估为true的_destroy键,否则将实例化一条新记录。

建议您在嵌套属性中传递id,将其视为应更新的现有记录。

答案 1 :(得分:1)

您很可能一开始就不需要accepts_nested_attributes_for

如果您希望用户能够通过选择来选择记录,那么除了创建选择并将material_id属性列入白名单之外,您实际上不需要执行任何其他操作:

<%= form_for(@material) do |f| %>
  <div class="field">
    <%= f.label :rubic_id %>
    <%= f.collection_select :rubic_id, Rubic.all :id, :name %>
  </div>
  <%= f.submit %>
<% end %>

选择将在参数中创建一个数组。

class MaterialsController
  # POST /materials
  def create
    @material = Material.new(material_params)
    if @material.save
      redirect_to @material
    else
      render :new
    end
  end

  private

    def material_params
      params.require(:material)
            .permit(:foo, :bar, material_ids: [])
    end
end

accepts_nested_attributes_for确实适用于需要在同一请求中创建/编辑嵌套资源的情况。您在这里使用它的唯一原因是:

  1. 用户应该能够以相同的形式创建材料。
  2. 您有一个包含其他属性(例如数量)的联接表,您希望用户能够设置这些属性。

您仍然可以与上面的选择一起执行1.,但是不能使用accepts_nested_attributes_for来设置简单的belongs_to关联。您也不想像用火箭打钉子一样。

答案 2 :(得分:1)

保留这个以防其他人可能像我一样遇到问题,通过 API 在 Rails 后端填充嵌套的子记录,但通过friendly_id 使用 hash_ids。

在尝试通过 API 修补 Rails 记录时遇到了这个问题。 第一个设置是反映 Rails 以嵌套形式发送记录值的方式。意思是,我有意构建了从前端发送到 Rails 后端的 params 哈希,就像典型的嵌套表单传输一样:

{ "children": {
      "0": {
            "name": "foo",
            "category_id": "1",
            "hash_id": "HDJPQT"
      }
}

accepts_nested_attributes_for 需要 id 来修补记录。否则,它将完全创建一个新记录。在我的场景中我不想要。我发送了 hash_id,因此无意中创建了新记录。

解决方案

暂时我不再复制嵌套的表单值哈希来发送到 Rails 后端。相反,我只是在来自 Javascript 前端的链式 fetch 查询中单独更新子记录。

注意: 如果您想继续发送一个镜像嵌套形式的哈希数组,可以根据您的需要将数据库表的主键更改为 hash_id 或 UUID。尚未测试此解决方案。