0

我有嵌套窗體和has_many關係的問題。商業案例:有實驗室及其供應商。供應商可以在實驗室之間共享。Rails 4與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 

結果的檢查上PARAMS AFTE [R提交形式:

參數:

{"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]) 

我缺少什麼,使其工作如預期?

回答

1

好像你需要明確地告訴lab_params從你需要通過像lab_suppliers哪些屬性:

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

試試吧,讓我知道。

+0

不,我試過了,仍然收到相同的錯誤。我認爲問題在於lab_suppliers params沒有嵌套在這裏的lab_params – Michal

+0

中:<%= fields_for:lab_suppliers do | ff | %>嘗試做<%= f.fields_for:lab_suppliers do | ff | %>所以,把f – loloso

+0

你是對的。更改爲f.fields_for使lab_suppliers表單值嵌套在lab_params中 – Michal

0

鏈接到其他崗位,幫助我找到工作的解決方案: [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 

評論: accepts_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 %> 

<%= F。提交%> <%端%>

控制器

評論: 沒有必要以允許供應商或lab_suppliers控制器的任何額外PARAMS

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 

評論:supplier_id:[]中lab_suppliers_attributes允許從多個下拉列表中傳遞值的數組