如何防止出现多个 simple_fields_for 表单?

How do I prevent multiple simple_fields_for forms showing up?

我有一个在迭代器中呈现的 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

以上对于没有 closed_positions.

@port_stock 记录非常有效

例如,该表单呈现如下:

请注意,Number of UnitsSale Price 字段在每一行中只显示一次(这是我所期望的)。

但是,一旦我在任何 PortStock 上创建了 closed_position,就会产生两个问题:

第一期

它将现有的已平仓头寸预填充为一个字段,然后为 closed_positions 呈现另一个空白字段,即像这样:

我想要的是它只呈现新表单,而不是在每一行上重新呈现现有的 closed_position 值。用户不应在此表单中编辑现有的已关闭头寸。

第二期

每当有多个平仓时,它会在每一行中呈现错误的仓位。

请注意呈现的每个值如何表示 num_units: 100 && price: 8.0,查看相同 closed_positions 的控制台输出:

=> [#<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",

正确的值实际上是:

  1. 单位数量:100 && 价格:8.0
  2. 单位数量:10 && 价格:7.95
  3. 单位数量:50 && 价格:7.9

我不明白为什么它为所有 port_stock 个对象输出相同的值。

如何解决我的 simple_fields_for 表单中的这两个问题?

好的,让我用我的逻辑不可靠来指导这个,但我是基于 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 没有直接关联,这是表单循环的内容。

所以,您真正发现的解决方案是同时声明两者,这是允许的:

Fields may reflect a model object in two ways - how they are named (hence how submitted values appear within the params hash in the controller) and what default values are shown when the form the fields appear in is first displayed. In order for both of these features to be specified independently, both an object name (represented by either a symbol or string) and the object itself can be passed to the method separately

并且文档建议同时声明两者,在您的情况下看起来像这样:

<%= 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| %>
      ...

虽然我显然会接受与正确答案相关的财富和名望,但公平地说,我不是一个人把你带到那里的。