【问题标题】:Rails 4 nested form with has_many, through and multiple select带有has_many,通过和多选的Rails 4嵌套表单
【发布时间】:2016-11-28 04:19:00
【问题描述】:

我对嵌套表单和 has_many 关系有疑问。商业案例:有实验室及其供应商。供应商可以在实验室之间共享。

模型

class Lab < ActiveRecord::Base
  has_many :lab_suppliers
  has_many :suppliers, through: :lab_suppliers
  accepts_nested_attributes_for :lab_suppliers
end

class Supplier < ActiveRecord::Base
  has_many :lab_suppliers
  has_many :labs, through: :lab_suppliers
  accepts_nested_attributes_for :lab_suppliers
end

class LabSupplier < ActiveRecord::Base
  belongs_to :lab
  belongs_to :supplier

  accepts_nested_attributes_for :lab
  accepts_nested_attributes_for :supplier
end

表格

<%= form_for(@lab) do |f| %>
  <div class="field">
    <%= f.label :code %><br>
    <%= f.text_field :code %>
  </div>
  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class"field">
    <%= fields_for :lab_suppliers do |ff| %>
      <%= ff.label :supplier_id %><br>
      <%= ff.collection_select :supplier_id, Supplier.all, :id, :name,  {include_blank: true}, {:multiple => true, :class=>""} %> 
    <% end %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

控制器

class LabsController < ApplicationController
  before_action :set_lab, only: [:show, :edit, :update, :destroy]

  # GET /labs/new
  def new
    @lab = Lab.new
    @lab.lab_suppliers.build
  end

  # POST /labs
  # POST /labs.json
  def create
    #raise params.inspect

    @lab = Lab.new(lab_params)

    @lab_supplier = @lab.lab_suppliers.new(params[:lab_suppliers])
    @lab_supplier.save
    @lab.save


    private

    def lab_params
      params.require(:lab).permit(:code, :name, lab_suppliers_attributes: [])
    end
end

提交表单后对参数的检查结果:

参数:

{"utf8"=>"✓",
 "authenticity_token"=>"...",
 "lab"=>{"code"=>"L01",
 "name"=>"xxx"},
 "lab_suppliers"=>{"supplier_id"=>["",
 "1",
 "3"]},
 "commit"=>"Create Lab"}

提交表单时,我收到 ActiveModel::ForbiddenAttributesError 上线:

@lab_supplier = @lab.lab_suppliers.new(params[:lab_suppliers])

为了让它按预期工作,我缺少什么?

【问题讨论】:

    标签: ruby-on-rails nested-forms has-many-through has-many multiple-select


    【解决方案1】:

    您似乎需要明确告诉lab_params 您需要传递lab_suppliers 中的哪些属性,例如:

    params.require(:lab).permit(:code, :name, lab_suppliers_attributes: [:supplier_id])
    

    试试看,然后告诉我。

    【讨论】:

    • 不,我已经尝试过了,但我仍然收到同样的错误。我认为问题在于 lab_suppliers 参数没有嵌套在 lab_params 中
    • 在这里: 尝试做 所以,把 f
    • 你是对的。更改为 f.fields_for 使 lab_suppliers 表单值嵌套在 lab_params 中
    【解决方案2】:

    链接到帮助我找到工作解决方案的其他帖子: [Rails nested form with multiple entries

    下面我提供了工作解决方案,展示了如何将多选中的值作为嵌套属性传递并将它们插入到数据库中。

    模型

    class Lab < ActiveRecord::Base
       has_many :lab_suppliers#, :foreign_key => 'lab_id', dependent: :destroy
       has_many :suppliers, through: :lab_suppliers
       accepts_nested_attributes_for :lab_suppliers, :allow_destroy => true
    end
    
    class Supplier < ActiveRecord::Base
      has_many :lab_suppliers
      has_many :labs, through: :lab_suppliers
    end
    
    class LabSupplier < ActiveRecord::Base
      belongs_to :lab
      belongs_to :supplier
    end
    

    评论: accept_nested_attributes_for 仅放在 has_many/has_one 一侧。不需要放在belongs_to一侧

    表格(实验室)

    <%= form_for(@lab) do |f| %>
      <div class="field">
        <%= f.label :code %><br>
        <%= f.text_field :code %>
      </div>
      <div class="field">
        <%= f.label :name %><br>
        <%= f.text_field :name %>
      </div>
        <div class"field">
    <%= f.fields_for :lab_suppliers do |ff| %>
      <%= ff.label :supplier_id %><br>
      <%= ff.collection_select :supplier_id, Supplier.all, :id, :name,  {include_blank: true}, {:multiple => true, :class=>""} %>
    <% end %>
    

    控制器

    评论: 无需在供应商或 lab_suppliers 控制器中允许任何其他参数

    class LabsController < ApplicationController
      before_action :set_lab, only: [:show, :edit, :update, :destroy]
    
    def new
      @lab = Lab.new
      @lab.lab_suppliers.build
    end
    
    
    def create
       @lab = Lab.new(lab_params)
    
    @startcount=1   #start counting from 1 because the first element in the array of nested params is always null
    @lab.lab_suppliers.each do |m|
      #raise lab_params[:lab_suppliers_attributes]["0"][:supplier_id][@startcount].inspect
      m.supplier_id = lab_params[:lab_suppliers_attributes]["0"][:supplier_id][@startcount]
      @startcount +=1
    end 
    
    respond_to do |format|
      if @lab.save
        lab_params[:lab_suppliers_attributes]["0"][:supplier_id].drop(@startcount).each do |m|
          @lab.lab_suppliers.build(:supplier_id => lab_params[:lab_suppliers_attributes]["0"][:supplier_id][@startcount]).save
          @startcount += 1
        end
        format.html { redirect_to labs_path, notice: 'Lab was successfully created.' }
        format.json { render :show, status: :created, location: @lab }
      else
        format.html { render :new }
        format.json { render json: @lab.errors, status: :unprocessable_entity }
      end
    end
    end
    
    
        private
    
    def lab_params
      params.require(:lab).permit(:name, :code, lab_suppliers_attributes: [supplier_id: [] ])
    end
    end
    

    注释:lab_suppliers_attributes 中的supplier_id: [] 允许传递来自多个下拉列表的值数组

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-30
      • 1970-01-01
      • 2016-02-18
      相关资源
      最近更新 更多