Rails 5:多对多关系不起作用
Rails 5: Many-to-Many Relationship Not Working
我正在尝试在 Rails 5 项目中创建多对多 table 关系。
一个Shop
可以有多个Categories
,在Shop_Categories
table.
中索引
不过我似乎错过了一个关键步骤。当我提交我的商店表格时,我收到软错误:"Unpermitted parameter: :shop_category"
我可以在 Rails 服务器日志中看到我的 shop_category
参数已成功发送,但是 Shop_Categories
table 根本没有更新。
我遗漏了什么,我可以更改什么以便在 Shop
视图表单上按保存更新 Shop_Categories
table?
这是我的代码。
店铺模型
class Shop < ApplicationRecord
belongs_to :type
has_many :shop_categories
has_many :categories, through: :shop_categories
accepts_nested_attributes_for :shop_categories
enum status: [:open, :closed, :opening_soon, :closing_soon]
end
Shop_Category型号
class ShopCategory < ApplicationRecord
belongs_to :shop
belongs_to :category
end
类别模型
class Category < ApplicationRecord
has_many :subcategories, dependent: :destroy
has_many :shop_categories
has_many :shops, through: :shop_categories
end
店长(节选)
def new
@shop = Shop.new
@shop.shop_categories.build
end
def create
@shop = Shop.new(shop_params)
@shop.open_date = params[:shop][:open_date]+"-01"
@shop.close_date = params[:shop][:close_date]+"-01"
if @shop.save
redirect_to @shop
else
render 'new'
end
end
def update
@shop = Shop.find(params[:id])
if @shop.update(shop_params)
redirect_to @shop
else
render 'edit'
end
end
private
def shop_params
params[:shop][:open_date] = params[:shop][:open_date]+"-01"
params[:shop][:close_date] = params[:shop][:close_date]+"-01"
params.require(:shop).permit(:shop_name, :type_id, :status,
:phone_number, :mobile_number, :email_address, :open_date,
:close_date, shop_categories_attributes: [ :shop_id, :category_id] )
end
商店表格视图(节选)
<p>
<%= form.label :shop_name %><br>
<%= form.text_field :shop_name %>
</p>
<%= form.fields_for :shop_category do |category_fields| %>
<p>
<%= category_fields.label :category %><br />
<%= category_fields.collection_select(:category_id, Category.all, :id, :category_name, include_blank: true) %>
</p>
<% end %>
<p>
<%= form.submit %>
</p>
最后,数据库架构
create_table "categories", force: :cascade do |t|
t.string "category_name"
t.text "category_description"
t.string "visible_category"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "shop_categories", force: :cascade do |t|
t.string "visible_category_override"
t.integer "shop_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["category_id"], name: "index_shop_categories_on_category_id"
t.index ["shop_id"], name: "index_shop_categories_on_shop_id"
end
create_table "shops", force: :cascade do |t|
t.string "shop_name"
t.integer "status"
t.integer "sale"
t.string "phone_number"
t.string "mobile_number"
t.string "email_address"
t.date "open_date"
t.date "close_date"
t.integer "type_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["type_id"], name: "index_shops_on_type_id"
end
如有任何建议,我们将不胜感激。我就是不知道我漏掉了哪一块拼图!
更新:包括开发日志和完整的商店表格。
开发日志
Started PATCH "/shops/1" for 127.0.0.1 at 2018-01-14 11:08:39 +0000
Processing by ShopsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2qydDj9JovMrg9VT6Lo5xbcNSHl5MH0ylmq3IMMX4iRTAVSgK6JlXWpG+CyuwQK6svZJn9wtnEnZANUlOZYzXA==",
"shop"=>{"shop_name"=>"test", "type_id"=>"1",
"shop_categories"=>{"category_id"=>"1"}, "subcategory_id"=>"",
"status"=>"open", "phone_number"=>"123", "mobile_number"=>"13212",
"email_address"=>"hello@test.com", "open_date"=>"2017-12",
"close_date"=>"2017-12"}, "commit"=>"Update Shop", "id"=>"1"}
Shop Load (0.5ms) SELECT "shops".* FROM "shops" WHERE "shops"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Unpermitted parameters: :shop_categories, :subcategory_id
(0.1ms) begin transaction
Type Load (0.2ms) SELECT "types".* FROM "types" WHERE "types"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.1ms) commit transaction
Redirected to http://localhost:3000/shops/1
Completed 302 Found in 10ms (ActiveRecord: 0.9ms)
完整 view/shops/_form.html.erb 文件
<%= form_with model: @shop, local: true do |form| %>
<% if @shop.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(@shop.errors.count, "error") %> prohibited
this shop from being saved:
</h2>
<ul>
<% @shop.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :shop_name %><br>
<%= form.text_field :shop_name %>
</p>
<p>
<%= form.label :type %><br />
<%= form.collection_select(:type_id, Type.all, :id, :type_name) %>
</p>
<%= form.fields_for :shop_categories do |category_fields| %>
<p>
<%= category_fields.label :category %><br />
<%= category_fields.collection_select(:category_id, Category.all, :id, :category_name, include_blank: true) %>
</p>
<% end %>
<p>
<%= form.label :subcategory %><br />
<%= form.grouped_collection_select :subcategory_id, Category.all, :subcategories, :category_name, :id, :visible_subcategory, include_blank: true %>
</p>
<p>
<%= form.label :status %><br />
<%= form.select :status, Shop.statuses.keys %>
</p>
<p>
<%= form.label :phone_number %><br>
<%= form.telephone_field :phone_number %>
</p>
<p>
<%= form.label :mobile_number %><br>
<%= form.telephone_field :mobile_number %>
</p>
<p>
<%= form.label :email_address %><br>
<%= form.email_field :email_address %>
</p>
<p>
<%= form.label :open_date %><br>
<%= form.month_field :open_date %>
</p>
<p>
<%= form.label :close_date %><br>
<%= form.month_field :close_date %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
应该是:shop_categories
,不是:shop_category
<%= f.fields_for :shop_categories do |category_f| %>
...
<% end %>
你在 Shop_Category 模型部分也有点迷失了我。实际 class 名称不同 (ShopSubcategory
) 并且它 belongs_to 是一个子类别?这也可能会导致一些错误。我猜你的意思是 ShopCategory
join 模型,它 belongs_to :category
更新
另外请务必在创建新表单时构建嵌套资源:
#shop_controller
def new
@shop = Shop.new
@shop.shop_categories.build
...
end
我正在尝试在 Rails 5 项目中创建多对多 table 关系。
一个Shop
可以有多个Categories
,在Shop_Categories
table.
不过我似乎错过了一个关键步骤。当我提交我的商店表格时,我收到软错误:"Unpermitted parameter: :shop_category"
我可以在 Rails 服务器日志中看到我的 shop_category
参数已成功发送,但是 Shop_Categories
table 根本没有更新。
我遗漏了什么,我可以更改什么以便在 Shop
视图表单上按保存更新 Shop_Categories
table?
这是我的代码。 店铺模型
class Shop < ApplicationRecord
belongs_to :type
has_many :shop_categories
has_many :categories, through: :shop_categories
accepts_nested_attributes_for :shop_categories
enum status: [:open, :closed, :opening_soon, :closing_soon]
end
Shop_Category型号
class ShopCategory < ApplicationRecord
belongs_to :shop
belongs_to :category
end
类别模型
class Category < ApplicationRecord
has_many :subcategories, dependent: :destroy
has_many :shop_categories
has_many :shops, through: :shop_categories
end
店长(节选)
def new
@shop = Shop.new
@shop.shop_categories.build
end
def create
@shop = Shop.new(shop_params)
@shop.open_date = params[:shop][:open_date]+"-01"
@shop.close_date = params[:shop][:close_date]+"-01"
if @shop.save
redirect_to @shop
else
render 'new'
end
end
def update
@shop = Shop.find(params[:id])
if @shop.update(shop_params)
redirect_to @shop
else
render 'edit'
end
end
private
def shop_params
params[:shop][:open_date] = params[:shop][:open_date]+"-01"
params[:shop][:close_date] = params[:shop][:close_date]+"-01"
params.require(:shop).permit(:shop_name, :type_id, :status,
:phone_number, :mobile_number, :email_address, :open_date,
:close_date, shop_categories_attributes: [ :shop_id, :category_id] )
end
商店表格视图(节选)
<p>
<%= form.label :shop_name %><br>
<%= form.text_field :shop_name %>
</p>
<%= form.fields_for :shop_category do |category_fields| %>
<p>
<%= category_fields.label :category %><br />
<%= category_fields.collection_select(:category_id, Category.all, :id, :category_name, include_blank: true) %>
</p>
<% end %>
<p>
<%= form.submit %>
</p>
最后,数据库架构
create_table "categories", force: :cascade do |t|
t.string "category_name"
t.text "category_description"
t.string "visible_category"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "shop_categories", force: :cascade do |t|
t.string "visible_category_override"
t.integer "shop_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["category_id"], name: "index_shop_categories_on_category_id"
t.index ["shop_id"], name: "index_shop_categories_on_shop_id"
end
create_table "shops", force: :cascade do |t|
t.string "shop_name"
t.integer "status"
t.integer "sale"
t.string "phone_number"
t.string "mobile_number"
t.string "email_address"
t.date "open_date"
t.date "close_date"
t.integer "type_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["type_id"], name: "index_shops_on_type_id"
end
如有任何建议,我们将不胜感激。我就是不知道我漏掉了哪一块拼图!
更新:包括开发日志和完整的商店表格。
开发日志
Started PATCH "/shops/1" for 127.0.0.1 at 2018-01-14 11:08:39 +0000
Processing by ShopsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2qydDj9JovMrg9VT6Lo5xbcNSHl5MH0ylmq3IMMX4iRTAVSgK6JlXWpG+CyuwQK6svZJn9wtnEnZANUlOZYzXA==",
"shop"=>{"shop_name"=>"test", "type_id"=>"1",
"shop_categories"=>{"category_id"=>"1"}, "subcategory_id"=>"",
"status"=>"open", "phone_number"=>"123", "mobile_number"=>"13212",
"email_address"=>"hello@test.com", "open_date"=>"2017-12",
"close_date"=>"2017-12"}, "commit"=>"Update Shop", "id"=>"1"}
Shop Load (0.5ms) SELECT "shops".* FROM "shops" WHERE "shops"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Unpermitted parameters: :shop_categories, :subcategory_id
(0.1ms) begin transaction
Type Load (0.2ms) SELECT "types".* FROM "types" WHERE "types"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.1ms) commit transaction
Redirected to http://localhost:3000/shops/1
Completed 302 Found in 10ms (ActiveRecord: 0.9ms)
完整 view/shops/_form.html.erb 文件
<%= form_with model: @shop, local: true do |form| %>
<% if @shop.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(@shop.errors.count, "error") %> prohibited
this shop from being saved:
</h2>
<ul>
<% @shop.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :shop_name %><br>
<%= form.text_field :shop_name %>
</p>
<p>
<%= form.label :type %><br />
<%= form.collection_select(:type_id, Type.all, :id, :type_name) %>
</p>
<%= form.fields_for :shop_categories do |category_fields| %>
<p>
<%= category_fields.label :category %><br />
<%= category_fields.collection_select(:category_id, Category.all, :id, :category_name, include_blank: true) %>
</p>
<% end %>
<p>
<%= form.label :subcategory %><br />
<%= form.grouped_collection_select :subcategory_id, Category.all, :subcategories, :category_name, :id, :visible_subcategory, include_blank: true %>
</p>
<p>
<%= form.label :status %><br />
<%= form.select :status, Shop.statuses.keys %>
</p>
<p>
<%= form.label :phone_number %><br>
<%= form.telephone_field :phone_number %>
</p>
<p>
<%= form.label :mobile_number %><br>
<%= form.telephone_field :mobile_number %>
</p>
<p>
<%= form.label :email_address %><br>
<%= form.email_field :email_address %>
</p>
<p>
<%= form.label :open_date %><br>
<%= form.month_field :open_date %>
</p>
<p>
<%= form.label :close_date %><br>
<%= form.month_field :close_date %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
应该是:shop_categories
,不是:shop_category
<%= f.fields_for :shop_categories do |category_f| %>
...
<% end %>
你在 Shop_Category 模型部分也有点迷失了我。实际 class 名称不同 (ShopSubcategory
) 并且它 belongs_to 是一个子类别?这也可能会导致一些错误。我猜你的意思是 ShopCategory
join 模型,它 belongs_to :category
更新
另外请务必在创建新表单时构建嵌套资源:
#shop_controller
def new
@shop = Shop.new
@shop.shop_categories.build
...
end