关于此主题至少有10个问题,但没有一个问题可以回答这个问题。许多问题与我没有的this之类的Rails表格有关,或与this或this更复杂的json结构有关。
关于已接受的答案的EDIT以及为什么这不完全重复
来自@CarlosRoque的答案中的链接问题最初看起来是同样的问题,但它只解决了这个特定问题的Rails方面。
如果您阅读了所有评论,您会看到多次尝试更改template_params
方法,以重命名或替换嵌套属性" template_items"使用" template_items_attributes"。这是必要的,因为Rails accepts_nested_attributes_for
需要" _attributes"要附加到名称,否则无法看到它。
如果您检查该答案中的猴子补丁代码以修复wrap_parameters以使其适用于嵌套属性,那么您仍然会遇到以下问题:它实际上找不到" template_items" (嵌套对象),因为它没有后缀" _attributes"。
因此,为了完全解决此问题,还必须修改客户端以将嵌套对象作为" template_items_attributes"发送。对于JS客户端,可以通过在对象上实现toJSON()方法来对序列化进行修改(例如here)。但请注意,当您反序列化JSON时,您需要手动创建该对象的实例以使toJSON()起作用(解释原因为here)。
我有一个简单的has_many / belongs_to:
型号:
class Template < ApplicationRecord
belongs_to :account
has_many :template_items
accepts_nested_attributes_for :template_items, allow_destroy: true
end
class TemplateItem < ApplicationRecord
belongs_to :template
validates_presence_of :template
enum item_type: {item: 0, heading: 1}
end
从客户端发送的json看起来像这样:
{
"id": "55e27eb7-1151-439d-87b7-2eba07f3e1f7",
"account_id": "a61151b8-deed-4efa-8cad-da1b143196c9",
"name": "Test",
"info": "INFO1234",
"title": "TITLE1",
"template_items": [
{
"is_completed": false,
"item_type": "item"
},
{
"is_completed": false,
"item_type": "heading"
}
]
}
有时每个template_item中都会有:id
和:content
属性(例如,在创建它们并且用户开始编辑它们之后)。
template_params
的{{1}}方法如下所示:
templates_controller
如果这是一个Rails表单,那么该行将是:
params.require(:template).permit(
:id, :account_id, :name, :title, :info,
template_items: [:id, :is_completed, :content, :item_type]
)
用于将嵌套子对象保存为父模板更新操作的一部分。
我尝试更改嵌套的param名称:
params.require(:template).permit(
:id, :account_id, :name, :title, :info,
template_items_attributes: [:id, :is_completed, :content, :item_type]
)
我可以看到他们仍被禁止:
def template_params
params.require(:template).permit(:id, :account_id, :name, :title, :info, template_items: [:id, :is_completed, :content, :item_type])
params[:template_items_attributes] = params.delete(:template_items) if params[:template_items]
Rails.logger.info params
end
我也试过合并:
{
"template" =><ActionController::Parameters {
"id" =>"55e27eb7-1151-439d-87b7-2eba07f3e1f7",
"account_id" =>"a61151b8-deed-4efa-8cad-da1b143196c9",
"name" =>"Test",
"info" =>"INFO1234",
"title" =>"TITLE1",
} permitted:false >,
"template_items_attributes" => [
<ActionController::Parameters {
"is_completed" =>false,
"item_type" =>"item"
} permitted:false >,
<ActionController::Parameters {
"is_completed" =>false,
"item_type" =>"item"
} permitted:false >
]
}
同样的问题。
那么我怎样才能确保它们被允许并包含在template_params中而不仅仅是执行.permit! (即,我不想盲目地允许一切)?
控制器更新方法:
template_params.merge! ({template_items_attributes:
params[:template_items]}) if params[:template_items].present?
UDPATE
如果我从客户端发送&#34; template_items_attributes&#34;而不是&#34; template_items&#34;在Rails的参数内部,然后执行建议的template_params,如下所示:
def update
Rails.logger.info "*******HERE*******"
Rails.logger.info template_params
@template.template_items = template_params[:template_items_attributes]
if @template.update(template_params)
render json: @template
else
render json: ErrorSerializer.serialize(@template.errors), status: :unprocessable_entity
end
end
它仍然不会为模板创建新的子项!
有了这个,我会在之前和之后输出参数,如下所示:
def template_params
params.require(:template).permit(:id, :account_id, :name, :title, :info, template_items_attributes: [:id, :is_completed, :content, :item_type])
end
这是来自这个场景的日志--Rails是STILL完全忽略了嵌入式阵列。请注意,在HERE之前的params显示允许:false,然后template_params不再包含子项&#34; template_items_attributes&#34;并标记为允许:true。
def update
Rails.logger.info params
Rails.logger.info "*******HERE*******"
Rails.logger.info template_params
if @template.update(template_params)
render json: @template
else
render json: ErrorSerializer.serialize(@template.errors), status: :unprocessable_entity
end
end
答案 0 :(得分:5)
我认为你忘记了params.require(:template).permit(...是一个返回值的方法,当你调用params以后修改它时你只修改了尚未被允许的params。你想要做的是交换执行参数操作时的顺序。
def template_params
params[:template][:template_items_attributes] = params[:template_items_attributes]
params.require(:template).permit(:id, :account_id, :name, :title, :info, template_items_attributes: [:id, :is_completed, :content, :item_type])
end
更新:wrap_parameters是罪魁祸首,因为它不包括被包装的参数中的嵌套参数。这解决了问题
更新:此答案实现了不同的解决方案 Rails 4 Not Updating Nested Attributes Via JSON
这是github中的一个长期开放请求!!疯 https://github.com/rails/rails/pull/19254
答案 1 :(得分:1)
<强>问题强>
您的问题出在update
操作中,您尝试保存尚未构建的@template
上的关联。因为没有&#39; ids&#39;使用散列进入,更新函数只是忽略它们。
解决方案
是迭代进入update
操作的关联哈希数组,并在@template
上调用update
之前在@template
上构建它们。
这里是sudo代码(没有尝试过,所以不要复制粘贴):
<强>模型强>
class Template < ApplicationRecord
belongs_to :account
has_many :template_items
accepts_nested_attributes_for :template_items, allow_destroy: true
end
class TemplateItem < ApplicationRecord
belongs_to :template, optional:true # <------ CHANGE
validates_presence_of :template
enum item_type: {item: 0, heading: 1}
end
强大的定义
params.require(:template).permit(
:id, :account_id, :name, :title, :info,
template_items_attributes: [:id, :is_completed, :content, :item_type]
)
更新操作
def update
template_params.template_items.each do |item_hash| # <------ CHANGE
@template.template_items.build(item_hash)
end
if @template.update(template_params)
render json: @template
else
render json: ErrorSerializer.serialize(@template.errors), status: :unprocessable_entity
end
end
答案 2 :(得分:0)
def template_params
template_params = params.require(:template).permit(:id, :account_id, :name,:title, :info, template_items: [:id, :is_completed, :content, :item_type])
template_params[:template_items_attributes] = template_params.delete :template_items
template_params.permit!
end