Rails,编辑操作不会使用同一模型的许多实例正确填充表单

时间:2017-09-30 00:49:12

标签: ruby-on-rails ruby forms

我是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 = 3observation = "bad",当我去编辑时,每个支票在其观察中都有“坏”,无论其ID如何。

我想知道如何编辑所有带有空白观察的检查但是创建的检查。

提前感谢您的时间!

4 个答案:

答案 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

简而言之,您的createcheck_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的顺序和上下文。