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

时间:2018-06-26 23:46:11

标签: ruby-on-rails ruby-on-rails-5 simple-form accepts-nested-attributes

我有一个在迭代器中呈现的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的{​​{1}}条记录,以上方法非常适用。

例如,该表单的呈现方式如下:

good-rendering-of-simple_form_for

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

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

第一期

它将现有的平仓头寸预先填充为一个字段,然后为PortStock渲染另一个空白字段,即:

first-issue

我要发生的事情是,它仅呈现新表单,而不重新呈现每行上现有的closed_position值。用户应该无法在此表单中编辑现有的平仓头寸。

第二期

只要有多个平仓,它就会在每一行中显示错误的位置。

wrong-values-rendered-for-each-closed-position

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

price: 8.0

正确的值实际上是:

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

我不明白为什么它为所有=> [#<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", 对象输出相同的值。

如何以port_stock格式解决这两个问题?

1 个答案:

答案 0 :(得分:1)

好的,让我指导我的逻辑并不牢固,但我将其基于ActionView::Helpers::FormHelper

无论使用simple_form还是标准的Rails助手,传递关联记录和关联模型之间都存在差异。

<%= form_for @record %>
  <%= fields_for @associated_record %>

vs。

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

虽然我显然会获得与正确答案相关的财富和名望,但是公平地承认我并不是一个人陪着你。