如何在有很多直通关系的情况下保存嵌套属性
How to save nested attributes on a has many through relationship
我遇到了一些问题,我对保存嵌套属性的正确方法有点困惑。
我有两个模型、位置和产品,还有一个名为 stock 的连接 table 连接这两个模型。
class Location < ApplicationRecord
has_many :stocks
has_many :products, :through => :stocks
end
class Product < ApplicationRecord
has_many :stocks
has_many :locations, :through => :stocks
accepts_nested_attributes_for :locations
end
class Stock < ApplicationRecord
belongs_to :location
belongs_to :product
end
在我的控制器中我有以下内容
class ProductsController < ApplicationController
def index
@products = Product.all
end
def new
@product = Product.new
@product.stocks.build
@locations = Location.all
end
def create
@product = Product.new(product_params)
if @product.save
flash[:notice] = "Successfully saved..."
redirect_to products_path
else
flash[:alert] = "Something went wrong, please check the values you entered"
redirect_to :back
end
end
但是我想我在操作上弄错了,因为什么也没发生。我想要的是在创建产品时显示所有可能的位置,以便用户可以 select 在哪些位置声明该产品应该存在。这自然是由库存模型跟踪的。
有大佬解惑吗?
编辑:我对此做了一些修改,
我的新观点
<div class="input-field">
<%= f.label :product_name %>
<%= f.text_field :name, autofocus: true %>
</div>
<div class="input-field">
<%= f.label :price %>
<%= f.text_field :price, autofocus: true %>
</div>
<%= f.fields_for :stocks do |ff| %>
<div class="input-field">
<%= ff.collection_select :location_id, Location.all, :id, :structured_location , {:prompt => "Please Select Locations for Product"}, {multiple: true} %>
<%= ff.label :locations %>
</div>
<% end %>
<div class="row margin-top x-4">
<div class="col s12 center-align">
<%= f.submit "Update", class: "btn wave-effect pink darken-1 btn-large" %>
</div>
</div>
在 product.rb 模型中
class Product < ApplicationRecord
has_many :stocks
has_many :locations, :through => :stocks
accepts_nested_attributes_for :stocks
end
现在我可以 select 位置,但是当我推送到产品控制器时,我发现 location_id 是不允许的
这是我的强参数
def product_params
params.require(:product).permit( :name,:price, {stocks_attributes: [:location_id]} )
end
这是在控制台中发送的参数
Parameters: {"utf8"=>"✓", "authenticity_token"=>"751Z5I5nBwmYJwFeiXO3jyBnPxqr3Pdz0ohDpN96F0ybE9V4yeUgjt2QYDYZfNvWG4CAdhvGaxIaCmqD6Ka8qw==", "product"=>{"name"=>"Tires Cleaner", "price"=>"4", "stocks_attributes"=>{"0"=>{"location_id"=>["", "1"]}}}, "commit"=>"Update"}
我认为问题是您需要在产品参数中嵌套位置关系的属性,例如:
params.require(:product).permit(:name, :price, {stocks_attributes: [:id, :location_id]})
因为它是 has_many 关系,所以您需要告诉强参数它是您要发送的数组,然后是特定于位置的属性。此外,当您稍后编辑时它会起作用,我也会允许 :id 字段:
params.require(:product).permit(:name, :price, stocks_attributes: [:id, location_id: []])
这将允许您 post 场地数组,然后当您稍后编写更新操作时,您还可以编辑场地(不允许使用 :id,它将重复该行)。
如果 Location 和 Product 之间的关系是直接的,则更容易。我看不出股票模型的重要性。一个位置有很多产品,一个产品有很多位置。因此,
class Location < ApplicationRecord
has_and_belongs_to_many :products
end
class Product < ApplicationRecord
has_and_belongs_to_many :locations
end
您需要迁移才能创建库存 table。那么你的嵌套形式应该是`
<%= f.fields_for :locations do |ff| %>
<div class="input-field">
<%= ff.collection_select :id, Location.all, :id, :structured_location , {:prompt => "Please Select Locations for Product"}, {multiple: true} %>
<%= ff.label :locations %>
</div>
<% end %>`
希望对您有所帮助。
`
我遇到了一些问题,我对保存嵌套属性的正确方法有点困惑。
我有两个模型、位置和产品,还有一个名为 stock 的连接 table 连接这两个模型。
class Location < ApplicationRecord
has_many :stocks
has_many :products, :through => :stocks
end
class Product < ApplicationRecord
has_many :stocks
has_many :locations, :through => :stocks
accepts_nested_attributes_for :locations
end
class Stock < ApplicationRecord
belongs_to :location
belongs_to :product
end
在我的控制器中我有以下内容
class ProductsController < ApplicationController
def index
@products = Product.all
end
def new
@product = Product.new
@product.stocks.build
@locations = Location.all
end
def create
@product = Product.new(product_params)
if @product.save
flash[:notice] = "Successfully saved..."
redirect_to products_path
else
flash[:alert] = "Something went wrong, please check the values you entered"
redirect_to :back
end
end
但是我想我在操作上弄错了,因为什么也没发生。我想要的是在创建产品时显示所有可能的位置,以便用户可以 select 在哪些位置声明该产品应该存在。这自然是由库存模型跟踪的。
有大佬解惑吗?
编辑:我对此做了一些修改,
我的新观点
<div class="input-field">
<%= f.label :product_name %>
<%= f.text_field :name, autofocus: true %>
</div>
<div class="input-field">
<%= f.label :price %>
<%= f.text_field :price, autofocus: true %>
</div>
<%= f.fields_for :stocks do |ff| %>
<div class="input-field">
<%= ff.collection_select :location_id, Location.all, :id, :structured_location , {:prompt => "Please Select Locations for Product"}, {multiple: true} %>
<%= ff.label :locations %>
</div>
<% end %>
<div class="row margin-top x-4">
<div class="col s12 center-align">
<%= f.submit "Update", class: "btn wave-effect pink darken-1 btn-large" %>
</div>
</div>
在 product.rb 模型中
class Product < ApplicationRecord
has_many :stocks
has_many :locations, :through => :stocks
accepts_nested_attributes_for :stocks
end
现在我可以 select 位置,但是当我推送到产品控制器时,我发现 location_id 是不允许的
这是我的强参数
def product_params
params.require(:product).permit( :name,:price, {stocks_attributes: [:location_id]} )
end
这是在控制台中发送的参数
Parameters: {"utf8"=>"✓", "authenticity_token"=>"751Z5I5nBwmYJwFeiXO3jyBnPxqr3Pdz0ohDpN96F0ybE9V4yeUgjt2QYDYZfNvWG4CAdhvGaxIaCmqD6Ka8qw==", "product"=>{"name"=>"Tires Cleaner", "price"=>"4", "stocks_attributes"=>{"0"=>{"location_id"=>["", "1"]}}}, "commit"=>"Update"}
我认为问题是您需要在产品参数中嵌套位置关系的属性,例如:
params.require(:product).permit(:name, :price, {stocks_attributes: [:id, :location_id]})
因为它是 has_many 关系,所以您需要告诉强参数它是您要发送的数组,然后是特定于位置的属性。此外,当您稍后编辑时它会起作用,我也会允许 :id 字段:
params.require(:product).permit(:name, :price, stocks_attributes: [:id, location_id: []])
这将允许您 post 场地数组,然后当您稍后编写更新操作时,您还可以编辑场地(不允许使用 :id,它将重复该行)。
如果 Location 和 Product 之间的关系是直接的,则更容易。我看不出股票模型的重要性。一个位置有很多产品,一个产品有很多位置。因此,
class Location < ApplicationRecord
has_and_belongs_to_many :products
end
class Product < ApplicationRecord
has_and_belongs_to_many :locations
end
您需要迁移才能创建库存 table。那么你的嵌套形式应该是`
<%= f.fields_for :locations do |ff| %>
<div class="input-field">
<%= ff.collection_select :id, Location.all, :id, :structured_location , {:prompt => "Please Select Locations for Product"}, {multiple: true} %>
<%= ff.label :locations %>
</div>
<% end %>`
希望对您有所帮助。
`