如何使用复选框创建嵌套表单的多个记录

时间:2016-07-29 00:17:13

标签: ruby-on-rails

我有一个Pizza模型和Topping模型,带有PizzaTopping连接表。比萨有很多浇头,浇头属于披萨。我是Rails的新手。

我的问题是试图了解如何创建一个嵌套表单,将多个记录添加到我的PizzaTopping连接表中。我还需要以复选框形式显示浇头。

<div class="form-horizontal">
  <%= form_for(@pizza) do |f| %>

混乱#1:

据我所知,这是在复选框中显示一个完整的模型,这是有效的,但我对控制器如何接受这个并在与比萨饼相关的浇头的连接表中创建记录感到困惑。我想要单独的记录(而不是一个顶级ID数组的属性):

PizzaTopping.create(id: 1, pizza_id: 1, topping_id: 1)
PizzaTopping.create(id: 2, pizza_id: 1, topping_id: 2)
PizzaTopping.create(id: 3, pizza_id: 1, topping_id: 3)

...

  <div class="form-group">
    <%= f.collection_check_boxes(:topping_ids, Topping.all, :id, :name) do |b| %>
      <%= b.check_box %>
      <%= b.label %>
    <% end %>
  </div>

或混乱#2:

这是一个嵌套的表单,但是如何从Topping模型中获取复选框中的toppings,如上所述,如何在控制器中对此进行编码以在连接表中添加记录。

<div class="form-group">
  <%= f.fields_for :toppings do |builder| %>
    <%= builder.check_box %> // confused what I would even do next

  <% end %>
</div>

...

    <%= f.submit %>
  <% end %>  
</div>

2 个答案:

答案 0 :(得分:1)

首先让我们通过pizza_toppings表设置间接的多对多关系。

class Pizza < ActiveRecord::Base
  has_many :pizza_toppings
  has_many :toppings, through: :pizza_toppings
end

class Topping < ActiveRecord::Base
  has_many :pizza_toppings
  has_many :pizzas, through: :pizza_toppings
end

class PizzaTopping < ActiveRecord::Base
  belongs_to :pizza
  belongs_to :topping
end

这可以让您将任意数量的比萨与任意数量的浇头相关联,ActiveRecord将为您处理加入:

@pizza = Pizza.find_by(name: 'Vesuvio') 
@pizza.toppings 
# => Topping( name: cheese ) ...
@pizza.toppings << Topping.find_by(name: 'Ham')
# inserts a record into the pizza_toppings table
# you can also do the inverse
@topping = Topping.find_by(name: 'Anchovies') 
@topping.pizzas
# => Pizza( name: 'Napoli' )

要通过复选框将其设置为任意或多对多关系,您可以使用collection_check_boxes helper

<% form_for(@pizza) do |f| %>
  <% f.collection_check_boxes(:topping_ids, Topping.all, :id, :name) %>
<% end %>

当你给模型一个has_many关联时,它得到一个_ids setter,它接受一组id并添加/删除关联,在这种情况下,ActiveRecord也足够聪明,知道它应该设置使用through选项时通过联接表进行的关联。

collection_check_boxes生成的复选框为您提供了 - 包含所选浇头的ID的参数中的数组。

请注意,除非您打算让用户在同一页面上创建比萨饼和浇头,否则您无需在此使用fields_for。另外,请确保将topping_ids参数列入白名单。

def pizza_params
  params.require(:pizza).permit(:name, topping_ids: [])
end

现在你让我都饿了。

答案 1 :(得分:0)

首先,如果您使用的是连接表,那么您需要以不同的方式组织关系,使用具有belongs_to关系的连接表是没有意义的,您要做的是组织您的关系以便比萨饼has_many:toppings和Topping has_many:pizzas并使用through :: pizza_toppings键。

现在你的第一次困惑, 如果你使用的是复选框,你可以希望收到的最多是该复选框的值,很可能就是id,然后在你拥有id数组后,你可以实例化记录,这可能是{{{ 1}}将实例化所选择的浇头的集合。 此外,如果您正确设置了关系,则无需显式创建PizzaTopping记录,这是一个连接表,在我看来,我更喜欢使用关系处理所有内容,regOpenResult = RegOpenCurrentUser(KEY_READ, &hKey); if (regOpenResult != ERROR_SUCCESS) { qCritical() << "Failed to call RegOpenCurrentUser(), Error is " << regOpenResult; } HKEY hSubKey; // Fails to get this hive, will get the default value "Unkown" RegOpenKeyEx(hKey, TEXT("Software\\Baidu\\BaiduYunGuanjia"), 0, KEY_READ, &hSubKey); 应该做的事情。把这一切都搞定的诀窍。

困惑二: 我不认为你要找的是一个嵌套的形式,因为你实际上并没有创建浇头,你只需要一个与披萨相关的浇头列表。嵌套表单是您想要创建/编辑然后写入关系的属性时,您的浇头已经预设,所以只需在表单中选中复选框,通常使用浇头ID的值。

希望这有帮助!