【问题标题】:How do I prevent multiple simple_fields_for forms showing up?如何防止出现多个 simple_fields_for 表单?
【发布时间】:2018-06-26 23:46:11
【问题描述】:

我有一个在迭代器中呈现的 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,看看这些相同的关闭位置的控制台输出:

=> [#<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 表单中的这两个问题?

【问题讨论】:

  • 是的,我在嵌套关联模型时总是遇到这个问题。可以&lt;%= f.simple_fields_for @cp, html: { class: "form-inline" } do |c| %&gt;吗?
  • @Chiperific 很棒的想法和建议。所以乍一看似乎解决了它,即它摆脱了重复的字段。但问题是 @cp 始终在控制器中声明,它与 @port_stock 相关,而不是迭代器中的本地 port_stock 变量。
  • @Chiperific 同样奇怪的是,我现在收到了这个错误:Unpermitted parameter: :closed_position,尽管我已经在我的强参数中声明了它:params.require(:port_stock).permit(:portfolio_id, :closed_position, closed_positions_attributes: [:num_units, :closer_id, :port_stock_id, :closed_price, :_destroy])。想法?
  • @Chiperific 您的建议有效,但我没有从simple_fields_for 表单处理程序中删除:closed_positions,而是将@cp 也添加到了表单处理程序中——即&lt;%= f.simple_fields_for :closed_positions, @cp, html: { class: "form-inline" } do |c| %&gt; 并且有效.我从另一个 SO question 中得到了这个建议。因此,如果您想将其添加为答案,我会接受。感谢您的建议!

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


【解决方案1】:

好的,让我用我的逻辑来指导这个,但我是基于ActionView::Helpers::FormHelper

不管simple_form 或标准Rails 助手,传递关联记录和关联模型之间存在差异。

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

对比

<%= form_for @record %>
  <%= fields_for :associated_model %>

而且我相信这与在新记录不存在时实例化新记录有关。

所以,我在 cmets 中的第一次尝试是建议使用更具体的记录变量:

:close_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| %>
      ...

虽然我显然会接受与正确答案相关的财富和名望,但公平地说,我并没有让你一个人到达那里。

【讨论】:

  • 太棒了。感谢您提供如此全面的答案和知识上的诚实。先生,您是一位绅士和一位学者!
猜你喜欢
  • 1970-01-01
  • 2020-12-27
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-04
相关资源
最近更新 更多