Rails 4 嵌套形式 has_many,通过和多个 select
Rails 4 nested form with has_many, through and multiple select
我对嵌套形式和 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])
我缺少什么才能让它按预期工作?
您似乎需要明确告诉 lab_params
您需要传递 lab_suppliers
中的哪些属性,例如:
params.require(:lab).permit(:code, :name, lab_suppliers_attributes: [:supplier_id])
试试看然后告诉我。
Link 给其他 post 帮助我找到工作解决方案的人:
[Rails nested form with multiple entries
下面我提供了工作解决方案,展示了如何将来自多个 select 的值作为嵌套属性传递并将它们插入到数据库中。
型号
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.submit %><% 结束 %>
控制器
评论:
无需在供应商或 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 中的 [] 允许传递多个下拉列表中的值数组
我对嵌套形式和 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])
我缺少什么才能让它按预期工作?
您似乎需要明确告诉 lab_params
您需要传递 lab_suppliers
中的哪些属性,例如:
params.require(:lab).permit(:code, :name, lab_suppliers_attributes: [:supplier_id])
试试看然后告诉我。
Link 给其他 post 帮助我找到工作解决方案的人: [Rails nested form with multiple entries
下面我提供了工作解决方案,展示了如何将来自多个 select 的值作为嵌套属性传递并将它们插入到数据库中。
型号
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.submit %><% 结束 %>
控制器
评论: 无需在供应商或 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 中的 [] 允许传递多个下拉列表中的值数组