我是Rails的新手,我正在做我的第一个项目。另外,英语不是我的母语,所以请耐心等待。
我遇到的问题是我有一个具有相同模型的多个实例的表单,数据正在正确创建,但是当我尝试编辑它时,表单以错误的方式填充。
我正在制作一个应用来检查一切是否符合规则。 要检查的项目是嵌套关联章节 - >子章节 - >检查
每次提交支票时,都会创建一个CheckRound,并且每张支票的信息都会单独存储在CheckResults中。
CheckRounds
has_many :check_results, inverse_of: :check_round, dependent: :destroy
accepts_nested_attributes_for :check_results, reject_if: proc { |att| att['observation'].blank? }
CheckResults
belongs_to :check_round, optional: true, inverse_of: :check_results
belongs_to :check
章节
has_many :subchapters
子章节
belongs_to: chapter
has_many: checks
检查
belongs_to :subchapter
has_many :check_results
表单显示所有章节以及嵌套的子章节和检查。 每个Check都显示其名称,并将text_area作为输入。
用户可以填写任何一项或多项支票。
<%= form_for(@check_round, :url => {:action => 'update', :client_id => @client.id, :project_id => @project.id}) do |f| %>
<% @chapters.each do |chapter| %>
<%= chapter.name %>
<% chapter.subchapters.each do |subchapter| %>
<%= subchapter.name %>
<% subchapter.checks.each do |check| %>
<%= f.fields_for :check_results do |result| %>
<%= check.name %>
<%= result.hidden_field(:check_id, :value => check.id) %>
<%= result.text_area(:observation, rows: 4, :id =>'obs' + check.id.to_s) %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
控制器是
def edit
@check_round = CheckRound.includes(:check_results).find(params[:id])
@chapters = Chapter.includes(subchapters: :checks).where("segment_id = ?", @project.segment_id).sorted
end
例如,如果我提交check.id = 3
有observation = "bad"
,当我去编辑时,每个支票在其观察中都有“坏”,无论其ID如何。
我想知道如何编辑所有带有空白观察的检查但是创建的检查。
提前感谢您的时间!
答案 0 :(得分:4)
好的,从我看到的两件事需要修复。
1,你的f.fields_for :check_results, @check_round.check_results.where(check_id: check.id) do |result|
需要一个额外的参数来指定它必须修改哪些check_results ...像这样的事情:
check
在完全相同的位置,以便check_round_params
变量指定正确的方式。
2de,您需要在控制器中允许嵌套参数,以便在提交时保存它们。通常,您应该在check_round控制器中看到一个名为 def check_round_params
params.require(:check_round_params).permit(
/*your needed params*/,
check_results_attributes: [:id, :check_id, :observation, /*all your nested params*/]
)
end
的方法。
这个人必须喜欢这一切才能发挥作用:
update
简而言之,您的create
和check_results_attributes:
操作会根据允许的参数进行操作,因此您需要在那里定义它们。 <div class="col-xs-1 col-sm-2 col-md-3 col-lg-4"></div>
是rails了解嵌套模型的params的方式。
以下是您可能感兴趣的一些文档:Nested attributes example
答案 1 :(得分:3)
我相信它的效果与你想要的一样(代码有一些简化):
检查
class Check < ApplicationRecord
belongs_to :subchapter
has_many :check_results
def check_results_for_form check_round_id
results = check_results.where(check_round_id: check_round_id)
results.any? ? results : check_results.build
end
end
CheckRoundsController
def edit
@check_round = CheckRound.find(params[:id])
@chapters = Chapter.includes(subchapters: :checks).all
end
edit.html.erb
<%= form_for(@check_round, :url => {:action => 'update'}) do |f| %>
<ul>
<% @chapters.each do |chapter| %>
<li>
<%= chapter.name %>
chapter
<ul>
<% chapter.subchapters.each do |subchapter| %>
<li>
<%= subchapter.name %>
subchapter
<ul>
<% subchapter.checks.each do |check| %>
<li>
<%= check.name %>
check
<br>
<%= f.fields_for :check_results, check.check_results_for_form(@check_round.id) do |result| %>
<%= result.hidden_field(:check_id, :value => check.id) %>
<%= result.text_area(:observation, rows: 4, :id =>'obs' + check.id.to_s) %>
<% end %>
</li>
<% end %>
</ul>
</li>
<% end %>
</ul>
</li>
<% end %>
<ul>
<%= f.submit %>
<% end %>
答案 2 :(得分:3)
这是我承诺的解决方案。
你已经定义了必须拒绝检查结果和空白观察结果,并且你的erb将涉及很多逻辑,我会把它全部放在一个辅助方法中,这样你的erb会更清洁。像这样:
#helpers/check_rounds_helper.rb
def edit_or_instantiate_nested_check_results(f, check_round, check, new_check_result)
if check.check_results
f.fields_for :check_results, check_round.check_results.where(check_id: check.id) do |result|
result.hidden_field(:check_id, :value => check.id)
result.text_area(:observation, rows: 4, :id =>'obs' + check.id.to_s)
end #end for the already present check results
# if u want to add a new check result event if the check is populated
f.fields_for :check_results, new_check_result do |new|
new.hidden_field(:check_id, :value => check.id)
new.text_area(:observation, rows: 4, :id =>'obs' + check.id.to_s)
end #end for the new check result
else #if there is no existing check result nest a form for a new one
f.fields_for :check_results, new_check_result do |new|
new.hidden_field(:check_id, :value => check.id)
new.text_area(:observation, rows: 4, :id =>'obs' + check.id.to_s)
end #end for the new check result
end #end if statement
end
然后在你看来:
<%= form_for(@check_round, :url => {:action => 'update', :client_id => @client.id, :project_id => @project.id}) do |f| %>
<% @chapters.each do |chapter| %>
<%= chapter.name %>
<% chapter.subchapters.each do |subchapter| %>
<%= subchapter.name %>
<% subchapter.checks.each do |check| %>
<%= check.name %>
<% new_check_result = CheckResult.new(check_round_id: @check_round.id, check_id = check.id) %>
<%= edit_or_instantiate_nested_check_results(f, @check_round, check, new_check_result) %>
<% end %>
<% end %>
<% end %>
<% end %>
那就是它;)。让我知道它是否有诀窍:D!
KR,
答案 3 :(得分:2)
您的问题是您正在重复显示check_results
的表单字段。查看视图代码的第7行:
<%= f.fields_for :check_results do |result| %>
这会在f.object
(@check_round
)上显示每个检查结果的字段。但是,check
中的每个subchapter
都会重复此代码。对于subchapter
中的每个chapter
,会重复该周围的块,并且chapter
中的每个@chapters
都会重复该周围的块。
提交表单时,check_results
的所有参数都具有相同的名称,它们不会通过章节,子章节或检查进行区分。因此,为observation
保存的唯一值是最后提交的值。
我认为您的案例的解决方案是仅显示与循环中当前检查相关联的check_result表单字段。一种方法是在视图代码的第7行开始循环:
<%= f.fields_for :check_results do |result| %>
<% if result.object.check == check %>
<%= result.hidden_field(:check_id, :value => check.id) %>
<%= result.text_area(:observation, rows: 4, :id =>'obs' + check.id.to_s) %>
<% end %>
<% end %>
<% end %>
您也可以独立于检查,子章节和章节的循环遍历check_results,但我假设您希望保留UI的顺序和上下文。