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!
КР,