【问题标题】:Rails: How to use fields_for with two objects of the same class in a single form?Rails:如何在一个表单中使用 fields_for 与同一类的两个对象?
【发布时间】:2011-07-04 17:57:19
【问题描述】:

我试图在 Rails 3 中使用 form_forfields_for 让我在一个页面上编辑两个对象(同一类),但我没有运气:第二个对象的 HTML 输入标签拿出与第一个对象相同的 ID。

具体情况:

  • 我有一个班级Card。我正在尝试遵循一般的 RESTful 模式。
  • 大多数卡片是独立的,但其中少数有第二个卡片对象,通过“链接”属性附属于第一个卡片对象。 (我将这些称为“多部分”卡片。)
  • 我希望能够使用标准卡片编辑页面(views/cards/edit.html.erb 和 views/cards/_form.html.erb)将卡片从独立模式切换到多部分模式。当用户在编辑页面上选择多部分模式时,我正在使用 JavaScript 在表单上显示第二组编辑字段。因此,every Card 的编辑表单需要 包含第二张卡片的表单字段,有可能成为正在编辑的主卡片中的“链接”卡片。
  • 第二张卡片的 HTML 字段应与第一张卡片的相同。我的字段和输入有一个复杂漂亮的 HTML 布局,我希望保持干燥并避免为第二张卡片的字段复制所有代码。

事实证明这确实有问题。我尝试过各种各样的事情,例如:

<%= form_for(@card) do |outer_form| %>
...
 <% [@card, @card2].each_with_index do |card, card_index| %>
  <%= fields_for card do |f| %>

这不起作用,因为第二个对象的 HTML 输入标记与第一个对象的 ID 相同。他们输出了 HTML &lt;select id="card_rarity" name="card[rarity]"&gt;,这显然是错误的。

我尝试将引用的行更改为说

 <% [@card, @card2].each_with_index do |card, card_index| %>
  <%= fields_for (card_index == 0 ? card : card.link) do |f| %>

希望这会提供像“card[link][rarity]”这样的 HTML 名称。 (编辑:)但它没有:即使使用fields_for card.link,它仍然会生成带有name="card[rarity]" 的表单字段。因此该页面有两个具有相同名称和 ID 的输入,并在提交时丢弃其中一个。

我试着说

 <% [@card, @card2].each_with_index do |card, card_index| %>
  <%= fields_for card, :as => (card_index == 0 ? "card" : "card2") do |f| %>

但这也没有用。 :as 参数似乎被完全忽略了。

谁能建议我在这里缺少的方法?我不觉得official documentation on form_for and fields_for 很有帮助。

(编辑添加:)特别是,肯定有一种方法可以在单个 Rails 表单中编辑同一类的两个不同对象的字段吗? fields_for 使得对任意数量的 不同 类的对象执行此操作变得微不足道 - 但是如何为同一类中的两个执行此操作?

非常感谢!

【问题讨论】:

  • 如何对两张卡的联动进行建模?自引用、1-1、1-n、n-n 等。
  • 一对一,暂时跟随 YAGNI。

标签: ruby-on-rails ruby-on-rails-3


【解决方案1】:

你说:

希望这会提供像“card[link][rarity]”这样的 HTML 名称,但问题是 Rails 会在对象上调用 class_name,而在大多数情况下 card.link 是 Nil。我不希望提交此表单以自动为所有卡创建一个虚拟链接卡,我认为这就是我认为在这种情况下会发生的情况。

我会更多地采用这种策略。在您的编辑控制器操作中,我将添加@card.link ||= Card.new 以防止零访问错误;在更新控制器操作中(或者如果您想推迟那里的逻辑,则在卡片模型本身中),确保丢弃空的“链接”卡片。

【讨论】:

  • 有道理,谢谢。我会试试这个策略。不过,我很好奇 - 肯定有一种方法可以在单个 Rails 表单中编辑同一类的两个不同对象的字段吗?
  • ...令人惊讶的是,这也不起作用。 fields_for @card.link 只是使用name="card[rarity]"&gt; 生成更多字段,因此表单包含相同命名输入的两个副本并丢弃其中一个。
  • 尝试做form_for @card do |f|,然后以f.fields_for :link do |link_f|的形式,并使用accepts_nested_attributes_for和适当的reject_if
  • @Rubish Gupta:谢谢 - 这很有效。在没有任何答案说明如何更普遍地做到这一点的情况下,我会接受你的答案,除非它是作为对杰里米答案的评论发布的。无论如何,感谢 Jeremy 和 Rubish 提供组件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-31
  • 1970-01-01
相关资源
最近更新 更多