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 г подачи формы:

Параметры:

{"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 не вложены в 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 (Lab)

<%= 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 %> 

<% = п.отправить%> конец <%%>

Контроллер

Комментарий: Там нет необходимости разрешать какие-либо дополнительные Params в Поставщиком или 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 

Комментарий: supplier_id: [] в lab_suppliers_attributes разрешает массив значений из множественного выпадающего списка, подлежащего передаче

 Смежные вопросы

  • Нет связанных вопросов^_^