我有一个奇怪的工作流程,首先创建子记录,然后通过嵌套表单将其与父记录关联。下面是一个使用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
之前,但我仍然觉得这应该是可能的。有没有一种方法可以让它工作,这样当保存父对象时,现有的子对象就与父对象相关联了?
2条答案
按热度按时间lndjwyie1#
如果在创建另一个记录时只需要关联现有记录,请使用
child_ids=
方法。collection_singular_ids=ids
用
ids
中的主键标识的对象替换集合。该方法加载模型并调用collection=
。在这个设置中,
Child
表不是一个连接表,但是如果你设置了 through 关联,*_ids
方法也可以工作。就像这样:https://stackoverflow.com/a/75972917/207090tmb3ates2#
accepts_nested_attributes_for
没有你想要的功能,你只能创建新的子节点,或者更新已经关联的子节点的属性,你不能添加现有的子节点。如果
id
存在,但不是parent.children
的一部分,那么您可以 * 覆盖children_attributes=
方法,以便它提供您正在寻找的功能(然后传递给super
以获得正常行为)。