ruby-on-rails Rails:在父记录之前创建子记录并抛出RecordNotFound错误

imzjd6km  于 2023-06-07  发布在  Ruby
关注(0)|答案(2)|浏览(136)

我有一个奇怪的工作流程,首先创建子记录,然后通过嵌套表单将其与父记录关联。下面是一个使用rspec的例子:
以下是模型:

class Parent < ApplicationRecord
  has_many :children, class_name: 'Child', dependent: :destroy

  accepts_nested_attributes_for :children, allow_destroy: true, reject_if: :all_blank
end

class Child < ApplicationRecord
  belongs_to :parent, foreign_key: 'child_id', optional: true
end

我的控制器是标准的:

def create
  @prent = Parent.new(parent_params)

  respond_to do |format|
    if @parent.save
      format.html { redirect_to @parent }
    else
      p @recipe.errors.full_messages
    end
  end
end

def parent_params
  params.require(:parent).permit(
    :name,
    children_attributes: [
      :id, :_destroy
    ]
  )
end

由于子项已经存在,我只是尝试将其与父项关联,而不是创建一个全新的记录。下面是我的测试,它失败并出现错误:

child = Child.create

expect {
  post "/parent", params: {
    parent: {
      name: "test",
      children_attributes: [{
        id: child.id
      }]
    }
  }.to change(Parent.all, :size).by(+1)
  .and change(Child.all, :size).by(0)
end

我收到的错误是

ActiveRecord::RecordNotFound:
   Couldn't find Child with ID=1 for Parent with ID=

显然这是因为Child存在于Parent之前,但我仍然觉得这应该是可能的。有没有一种方法可以让它工作,这样当保存父对象时,现有的子对象就与父对象相关联了?

lndjwyie

lndjwyie1#

如果在创建另一个记录时只需要关联现有记录,请使用child_ids=方法。
collection_singular_ids=ids
ids中的主键标识的对象替换集合。该方法加载模型并调用collection=

  • https:api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many*
# db/migrate/20230601025957_create_parents.rb
class CreateParents < ActiveRecord::Migration[7.0]
  def change
    create_table :parents
    create_table :children do |t|
      t.references :parent
    end
  end
end
# app/models/parent.rb
class Parent < ApplicationRecord
  has_many :children
end

# app/models/child.rb
class Child < ApplicationRecord
  belongs_to :parent, optional: true
end
# spec/requests/parent_spec.rb
require "rails_helper"
RSpec.describe "Parents", type: :request do
  it "POST /parents" do
    child = Child.create!
    expect do
      post "/parents", params: {parent: {child_ids: [child.id]}}
    end.to(
      change(Parent, :count).by(1).and(
        change(Child, :count).by(0)
      )
    )
  end
end
# 1 example, 0 failures

在这个设置中,Child表不是一个连接表,但是如果你设置了 through 关联,*_ids方法也可以工作。就像这样:https://stackoverflow.com/a/75972917/207090

tmb3ates

tmb3ates2#

accepts_nested_attributes_for没有你想要的功能,你只能创建新的子节点,或者更新已经关联的子节点的属性,你不能添加现有的子节点。
如果id存在,但不是parent.children的一部分,那么您可以 * 覆盖children_attributes=方法,以便它提供您正在寻找的功能(然后传递给super以获得正常行为)。

相关问题