问题:当我点击{{1>时,它们在现有嵌套属性的基础上创建,而不是更新嵌套属性。相关#update
可能的原因:我认为问题在于我在Rails'features_controller.rb
中缺乏理解。我认为细分是在我的视图中,我如何渲染持久的嵌套属性,和/或我如何指定嵌套属性的id失败,导致它只是创建一个新的
feature.rb
form_for
features_controller.rb
class Feature < ActiveRecord::Base
...
has_many :scenarios
accepts_nested_attributes_for :scenarios,
allow_destroy: true,
reject_if: :all_blank
...
end
_form.html.haml(简化)
def update
...
project = Project.find(params[:project_id])
@feature = Feature.find(params[:id])
if @feature.update_attributes(feature_params)
# checking feature_params looks good...
# feature_params['scenarios'] => { <correct object hash> }
redirect_to project
else
render :edit
end
end
...
private
def feature_params
params.require(:feature).permit(:title, :narrative, :price, :eta, scenarios_attributes[:description, :_destroy])
end
我确信有更好的方法来实现= form_for [@project, @feature] do |f|
...
- if @feature.new_record? -# if we are creating new feature
= f.fields_for :scenarios, @feature.scenarios.build do |builder|
= builder.label :description, "Scenario"
= builder.text_area :description, rows: "3", autocomplete: "off"
- else -# if we are editing an existing feature
= f.fields_for :scenarios do |builder|
= builder.label :description, "Scenario"
= builder.text_area :description, rows: "3", autocomplete: "off"
检查。我也使用一些Javascript钩子来创建动态嵌套属性表单(我已经遗漏了),受Railscast #196 Nested Model Form (revised)
我非常喜欢处理这些嵌套表单的非常好的 Rails-y 实现。
答案 0 :(得分:40)
尝试将:id
添加到:scenario_attributes
方法的feature_params
部分。您只有描述字段和允许销毁的能力。
def feature_params
# added => before nested attributes
params.require(:feature).permit(:id, :title, :narrative, :price, :eta, scenarios_attributes => [:id, :description, :_destroy])
end
正如@vinodadhikary建议的那样,您不再需要检查功能是否是新记录,因为Rails(特别是使用form_for
方法)将为您执行此操作。
更新:
您无需在表单中定义if @feature.new_record? ... else
。使用form_for
时,Rails会照顾它。 Rails会根据create
检查操作是update
还是object.persisted?
,因此,您可以将表单更新为:
= form_for [@project, @feature] do |f|
...
= f.fields_for :scenarios, @feature.scenarios.build do |builder|
= builder.label :description, "Scenario"
= builder.text_area :description, rows: "3", autocomplete: "off"
答案 1 :(得分:4)
正如@ Philip7899在接受的答案中提到的那样,允许用户设置id
意味着他们可以“窃取”属于另一个用户的子记录。
然而,Rails accepts_nested_attributes_for
实际检查id
并加注:
ActiveRecord::RecordNotFound:
Couldn't find Answer with ID=5 for Questionnaire with ID=5
基本上,在儿童协会中寻找ids(再次,如@glampr所述)。因此,找不到属于另一个用户的子记录。
最终, 401 是响应状态(与ActiveRecord::RecordNotFound
中通常的404不同)
遵循我用来测试行为的一些代码。
let :params do
{
id: questionnaire.id,
questionnaire: {
participation_id: participation.id,
answers_attributes: answers_attributes
}
}
end
let :evil_params do
params.tap do |params|
params[:questionnaire][:answers_attributes]['0']['id'] = another_participant_s_answer.id.to_s
end
end
it "doesn't mess with other people's answers" do
old_value = another_participant_s_answer.value
put :update, evil_params
expect(another_participant_s_answer.reload.value).to eq(old_value) # pass
expect(response.status).to eq(401) # pass
end
总之,如上所述,将id
添加到允许的参数中是正确的,安全。
迷人的Rails。