Rails, действие редактирования не заполняет форму правильно со многими экземплярами одной и той же модели

Я новичок в 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

Форма отображает все главы и вложенные субчины и чеки. Каждая проверка отображает свое имя и имеет текстовое поле в качестве ввода.

Пользователь может заполнить ни один или несколько проверок.

<%= 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", когда я перехожу к редактированию, каждая проверка имеет "плохое" в своем наблюдении независимо от его идентификатора.

Я хочу знать, как я могу показать при редактировании все проверки с пустым наблюдением, но те, которые были созданы.

Заранее благодарим за ваше время!

Ответ 1

Я считаю, что он работает так, как вам хочется (код с некоторыми упрощениями):

Проверка

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

Хорошо, из того, что я вижу 2 вещи, которые необходимо исправлять.

1, ваш f.fields_for :check_results do |result| требуется дополнительный параметр, чтобы указать, какие check_results он должен изменить... такие вещи, как это:

f.fields_for :check_results, @check_round.check_results.where(check_id: check.id) do |result| в том же месте, поэтому переменная check указывает правильный путь.

2de, вы должны разрешить свои вложенные параметры в контроллере, чтобы они могли быть сохранены при отправке. Обычно вы должны увидеть метод под названием check_round_params в вашем контроллере 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: - это способ, которым рельсы понимают эти параметры для вложенных моделей.

Вот некоторая документация, которая может показаться вам интересной: Пример вложенных атрибутов

Ответ 3

Ваша проблема в том, что вы повторяете отображение полей формы для 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 независимо от циклов для проверок, подчисток и разделов, но я предполагаю, что вы хотите сохранить этот порядок и контекст для пользовательского интерфейса.

Ответ 4

Вот решение, которое я обещал.

Считает, что вы уже определили, что результаты проверки с пустыми наблюдениями должны быть отклонены, и для вашей эры потребуется большая логика, связанная с вашим 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!

КР,