Rails 4:提交表单中相关对象的数组

时间:2014-03-08 22:16:04

标签: ruby-on-rails forms ruby-on-rails-4

这已成为关于Rails如何神奇地知道如何创建连接表记录而不指定它来创建这些记录的问题。

我正在构建一个电子商务解决方案,用户可以在其中购买软件包,并且在这些软件包中有许多项目。我创建了一个表单来处理包的创建,该表还允许您以相同的形式添加要放在包中的项目。

为了实现这一目标,我创建了一个package模型,item模型和一个加入两个模型的package_item模型(并非每个项目都属于一个包,我希望用户能够添加未包含在包中的其他项目,所以我认为这是将两者联系起来的最佳方式。

我的思考过程是为可添加到包中的项创建复选框并将其作为数组提交,然后将items数组作为允许参数添加到包控制器中的strong参数方法中。

这是来自app / views / packages / _form.html.erb的表单:

<%= form_for(@package) do |f| %>
  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :description %><br>
    <%= f.text_area :description %>
  </div>
  <div class="field">
    <h3>Items:</h3>
      <% @items.each do |item| %>
        <%= check_box_tag :item_ids, item.id, @package.package_items.include?(item), name: 'package[item_ids][]' %>
        <!-- somehow, this displays the items correctly and allows me to submit them as an array -->

      <% end %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

packages_controller(没有与我的问题无关的操作):

class PackagesController < ApplicationController
  before_action :set_package, only: [:show, :edit, :update, :destroy]

  def index
    @packages = Package.all
  end

  def new
    @package = Package.new
    @items = Item.all
  end

  def create
    @package = Package.new(package_params)
    respond_to do |format|
      if @package.save
        # I thought the next block would be necessary, but apparently it isn't
        # package_params[:item_ids].each do |item|
          # @package.package_items.build(item_id: item)
        # end
        format.html { redirect_to @package, notice: 'package was successfully created.' }
        format.json { render action: 'show', status: :created, location: @package }
      else
        format.html { render action: 'new' }
        format.json { render json: @package.errors, status: :unprocessable_entity }
      end
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_package
      @package = Package.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def package_params
      params.require(:package).permit(:name, :description, :item_ids => [])
    end    
end

为了处理包项的创建,在创建包之后,我遍历项目数组,为每个项目创建一个新的@package.package_items记录。

更新 上面代码块中注释掉的代码是我原先认为需要包含的代码,以便创建连接表记录。但是,我在运行该代码时发现我正在创建重复记录。所以我删除了那个块并且实现了Rails以某种方式直观地知道如果在参数中包含项目ID数组时继续创建package_items记录。任何人都可以解释Rails如何知道如何做到这一点?

我也很好奇是否有更好或更有效的方法来完成我在这里所做的事情。任何意见都将不胜感激。

以下是我的模型供参考:

package.rb:

class Package < ActiveRecord::Base
  has_many :items, through: :package_items
  has_many :package_items
end

item.rb的:

class Item < ActiveRecord::Base
  has_many :package_items
  has_many :packages, through: :package_items
end

package_item.rb:

class PackageItem < ActiveRecord::Base
  belongs_to :package
  belongs_to :item
end

1 个答案:

答案 0 :(得分:1)

自从这个问题以来,我一路走来。答案在package_params内 - 我通过允许的参数发送item_ids。我的模型has_many :items, through: :package_items,允许我这样做并自动创建相关对象。