Как предотвратить появление нескольких форм simple_fields_for?
У меня есть форма simple_fields_for, которая отображается внутри итератора, например, так:
<%= simple_form_for @port_stock, url: port_stocks_sell_order_path, method: :post, html: { class: "form-inline" } do |f| %>
<% @buy_port_stocks.each do |port_stock| %>
<%= f.simple_fields_for :closed_positions, html: { class: "form-inline" } do |c| %>
<div class="form-group">
<%= c.input_field :port_stock_id, as: :hidden, value: port_stock.id %>
<%= c.input_field :num_units, id: "sell-ps-#{port_stock.id}", placeholder: "Number of Units", class: "form-control mx-sm-3" %>
<%= c.input_field :closed_price, id: "sale-price-for-ps-#{port_stock.id}", placeholder: "Sale Price", class: "form-control mx-sm-3" %>
</div>
<% end %>
<% end %>
<% end %>
В моем контроллере у меня есть это:
@port_stock = current_user.port_stocks.friendly.find(params[:id])
@buy_port_stocks = current_user.port_stocks.buy.joins(:stock).where(stocks: { ticker: @stock.ticker})
@cp = @port_stock.closed_positions.build
мой PortStock.rb
модель:
has_many :closed_positions, dependent: :destroy
accepts_nested_attributes_for :closed_positions, allow_destroy: true
мой ClosedPosition.rb
модель:
class ClosedPosition < ApplicationRecord
belongs_to :closer, class_name: "PortStock", foreign_key: "closer_id"
belongs_to :closed, class_name: "PortStock", foreign_key: "port_stock_id"
end
Вышесказанное прекрасно работает для @port_stock
записи, которые не имеют closed_positions
,
Например, эта форма отображается так:
Обратите внимание, что Number of Units
а также Sale Price
поле появляется только один раз в каждой строке (что я и ожидаю).
Однако, как только я создаю closed_position
на любом PortStock
это создает две проблемы:
Первая проблема
Он предварительно заполняет существующую закрытую позицию как поле, а затем отображает другое пустое поле для closed_positions
т.е. так:
Я хочу, чтобы он просто отображал новую форму, а не повторно отображал существующие значения closed_position в каждой строке. Пользователь не должен иметь возможность редактировать существующие закрытые позиции в этой форме.
Второй выпуск
Всякий раз, когда есть несколько закрытых позиций, он отображает неправильные позиции в каждой строке.
Обратите внимание, что каждое отображаемое значение говорит num_units: 100
&& price: 8.0
посмотрите на вывод консоли тех же закрытых_позиций:
=> [#<ClosedPosition:0x00007ff13e77c6d0
id: 9,
closer_id: 2,
port_stock_id: 17,
num_units: 100,
closed_price: 8.0,
ticker: "CAC",
#<ClosedPosition:0x00007ff13e77c2e8
id: 10,
closer_id: 3,
port_stock_id: 18,
num_units: 10,
closed_price: 7.95,
ticker: "CAC",
#<ClosedPosition:0x00007ff13e77c018
id: 11,
closer_id: 10,
port_stock_id: 19,
num_units: 50,
closed_price: 7.9,
ticker: "CAC",
Правильные значения на самом деле:
- Количество штук: 100 && Цена: 8.0
- Количество штук: 10 && Цена: 7,95
- Количество штук: 50 && Цена: 7,9
Я не понимаю, почему он выдает одинаковое значение для всех port_stock
объекты.
Как мне исправить эти две проблемы в моем simple_fields_for
форме?
1 ответ
Хорошо, позвольте мне тренировать это с моей логикой, но я основываюсь на ActionView::Helpers::FormHelper
Невзирая на simple_form
или стандартные помощники Rails, есть разница между передачей связанной записи и связанной модели.
<%= form_for @record %>
<%= fields_for @associated_record %>
против
<%= form_for @record %>
<%= fields_for :associated_model %>
И я верю, что это связано с созданием новой записи, когда ее нет.
Итак, мое первое колебание в комментариях состояло в том, чтобы предложить использовать более конкретную переменную записи:
: closed_positions @cp
Вроде так:
<%= simple_form_for @port_stock, url: port_stocks_sell_order_path, method: :post, html: { class: "form-inline" } do |f| %>
<% @buy_port_stocks.each do |port_stock| %>
<%= f.simple_fields_for @cp, html: { class: "form-inline" } do |c| %>
...
Как вы прокомментировали, это не идеальное решение, но оно решает повторяющиеся поля.
Но, как показывает ваш контроллер, @cp
не является прямой ассоциацией с @buy_port_stocks
, что является то, что форма зацикливается.
Итак, решение, которое вы действительно обнаружили, это объявить и то, и другое:
Поля могут отражать объект модели двумя способами - как они называются (следовательно, как представленные значения отображаются в хэше params в контроллере) и какие значения по умолчанию отображаются при первом отображении формы, в которой отображаются поля. Чтобы обе эти функции были определены независимо, как имя объекта (представленное символом или строкой), так и сам объект могут быть переданы методу отдельно
И документы предлагают объявить оба, что в вашем случае будет выглядеть так:
<%= simple_form_for @port_stock, url: port_stocks_sell_order_path, method: :post, html: { class: "form-inline" } do |f| %>
<% @buy_port_stocks.each do |port_stock| %>
<%= f.simple_fields_for :closed_positions, @cp, html: { class: "form-inline" } do |c| %>
...
Хотя я, несомненно, возьму богатство и славу, связанные с правильным ответом, справедливо признать, что я не привел вас туда одного.