如何为 has_many 创建控制器和视图并通过 ruby 中的关系创建 rails
How to create controller and views for has_many and through relationship in ruby on rails
请放轻松,因为我只是一个初学者,在过去的两天里,我一直在为这个问题伤脑筋。总而言之,我有一个 user 和 productplan ,当用户选择某个产品计划(单选按钮或复选框)时,我希望将当前用户 ID 和所选产品 ID 存储在名为 userproducts 的连接 table 中
但由于某种原因我无法存储数据,我不知道我哪里出错了,感谢任何帮助,谢谢。
型号:
class User < ActiveRecord::Base
has_many :userproducts
has_many :productplans, :through=>:userproducts
end
class productplan < ApplicationRecord
has_many :userproducts
has_many :users, :through => :userproducts
end
class Userproduct < ApplicationRecord
belongs_to :user
belongs_to :productplan
end
ProductPlan 控制器:
class ProductPlanController < ApplicationController
before_action :authenticate_user!
def new
@user=User.new
end
end
def create
@user = User.create(user_params)
if @user.save
render :action => 'index'
else
render :action =>'new'
end
private
def user_params
params.require(:user).permit(:productplan_ids => [])
end
end
观看次数:
productplan/_form.html.erb
<%= form_for @user,:url=> productplan_index_path,:method => :post do
|f|%>
<%= f.collection_check_boxes :productplan_ids, ProductPlan.all, :id,
:productplan_name %>
<%= f.submit %>
<% end %>
由于控制器上的示例和关于 has_many 的视图较少,我很确定我在其中有很多错误。另外,当我尝试提交表单时,我得到了这个日志:
enterStarted POST "/Productplan" for 127.0.0.1 at 2017-11-28 11:08:29 -0600
Processing by ProductPlanController#create as HTML
Parameters
{"utf8"=>"✓","authenticity_token"=>
"mi9RwHCLPKItXai67t5iX0RYrDoE6TN9T
iZzJFYELbKVDlHbhpeNmOC0q2gu1iXyWNaUqGSEsPrBEjcUSE2yYw==", "user"= >
{"productsku_ids"=>["", "4", "7"]}, "commit"=>"Create User"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" =
ORDER BY "users"."id" ASC LIMIT [["id", 3], ["LIMIT", 1]]
ProductPlan Load (2.6ms) SELECT "productplans".* FROM "productplans" WHERE
"productplans"."id" IN (4, 7)
(0.5ms) BEGIN
Provider Load (0.5ms) SELECT "providers".* FROM "providers" WHERE
"providers"."id" = LIMIT [["id", 1], ["LIMIT", 1]]
CACHE Provider Load (0.0ms) SELECT "providers".* FROM "providers" WHERE
"providers"."id" = LIMIT [["id", 1], ["LIMIT", 1]]
(0.6ms) ROLLBACK
Rendering ups/new.html.erb within layouts/application
ProductPlan Load (0.9ms) SELECT "productplans".* FROM "productplans"
Rendered productplans/_form.html.erb (4.6ms)
Rendered productplans/new.html.erb within layouts/application (6.4ms)
Rendered _navbar.html.erb (0.7ms)
Completed 200 OK in 191ms (Views: 102.1ms | ActiveRecord: 14.6ms) here
由于某种原因它回滚了,我也需要获取当前用户。
dependent_new GET /dependent/new(.:format) dependent#new
dependent_create GET /dependent/create(.:format) dependent#create
summary_root GET /summary/index(.:format) summary#index
home_plans GET /home/plans(.:format) home#plans
thanks GET /thanks(.:format) charges#thanks
authenticated_root GET / home#roothome
productplan_index GET /productplan(.:format) productplan#index
POST /productplan(.:format) productplan#create
new_productplan GET /productplan/new(.:format) productplan#new
edit_productplan GET /productplan/:id/edit(.:format) productplan#edit
productplan GET /productplan/:id(.:format) productplan#show
PATCH /productplan/:id(.:format) productplan#update
PUT /productplan/:id(.:format) productplan#update
DELETE /productplan/:id(.:format) productplan#destroy
userproducts GET /userproducts(.:format) userproducts#index
POST /userproducts(.:format) userproducts#create
new_userproduct GET /userproducts/new(.:format) userproducts#new
edit_userproduct GET /userproducts/:id/edit(.:format) userproducts#edit
userproduct GET /userproducts/:id(.:format) userproducts#show
PATCH /userproducts/:id(.:format) userproducts#update
PUT /userproducts/:id(.:format) userproducts#update
DELETE /userproducts/:id(.:format) userproducts#destroy
ups POST /ups(.:format) ups#create
new_up GET /ups/new(.:format) ups#new
root GET / home#index
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
所以我按照@jvillian 的要求修改了我的代码,但问题仍然存在,这是我的新代码。
请注意我将用户产品重命名为 ups,
型号:
class User < ActiveRecord::Base
has_many :ups
has_many :productplans, through: :ups
end
class productplan < ApplicationRecord
has_many :ups
has_many :users, :through => :ups
end
class Up < ApplicationRecord
belongs_to :user
belongs_to :productplan
end
Ups 控制器:
class UpsController < ApplicationController
before_action :authenticate_user!
def create
current_user.productplans<<Productplan.where(id: productplans_ids)
render :action => 'index'
end
private
def productplan_ids
params.require(:up).permit(productplan_ids:[])
end
end
观看次数ups/_form.html.erb
<%= form_for :up,:url=> ups_path do |f| %>
<%= f.collection_check_boxes :productplan_ids, Productplan.all, :id,
:productplan_name %>
<%= f.submit %>
<% end %>
日志:
Started GET "/ups" for 127.0.0.1 at 2017-11-28 14:43:50 -0600
Processing by UpsController#index as HTML
User Load (1.6ms) SELECT "users".* FROM "users" WHERE "users"."id" =
ORDER BY "users"."id" ASC LIMIT [["id", 3], ["LIMIT", 1]]
Rendering ups/index.html.erb within layouts/application
Productplan Load (0.7ms) SELECT "productplans".* FROM "productplans"
Rendered ups/_form.html.erb (42.5ms)
Rendered ups/index.html.erb within layouts/application (47.7ms)
Rendered _navbar.html.erb (0.9ms)
Completed 200 OK in 347ms (Views: 235.0ms | ActiveRecord: 15.0ms)
Started POST "/ups" for 127.0.0.1 at 2017-11-28 14:43:53 -0600
Processing by UpsController#create as HTML
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"g7lLydleU7J14G7N9avWSK87E4BbkPQ9sdL
Q9X2bbSCMmEvSL0LiiLgJbR81o5Hls7UrEjv9d7o+5pTFY9Ly8Q==", "up"=>
{"productplan_ids"=>["", "4"]}, "commit"=>"Save Up"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" =
ORDER BY "users"."id" ASC LIMIT [["id", 3], ["LIMIT", 1]]
Productplan Load (0.7ms) SELECT "productplans".* FROM "productplans" WHERE
"productplans"."id" = [["id", nil]]
(0.4ms) BEGIN
(0.3ms) COMMIT
Rendering ups/index.html.erb within layouts/application
Productplan Load (0.6ms) SELECT "productplans".* FROM "productplans"
Rendered ups/_form.html.erb (4.9ms)
Rendered ups/index.html.erb within layouts/application (7.9ms)
Rendered _navbar.html.erb (1.0ms)
Completed 200 OK in 201ms (Views: 183.4ms | ActiveRecord: 3.0ms)
route.rb
devise_scope :user do
# write all your routes inside this block
resources :productplan
resources :ups
end
Ups中仍然没有插入数据table,也没有报错。虽然根据日志文件它没有回滚,但问题仍然存在。
更新:从 OP
修改代码后
更近了!
如您所见:
Productplan Load (0.7ms) SELECT "productplans".* FROM "productplans" WHERE "productplans"."id" = [["id", nil]]
我们没有得到 productplan_ids
完全正确(如 nil
所示)。如果您在控制台中执行以下操作:
> params = ActionController::Parameters.new(up: {productplan_ids: ["","4"]})
> params.require(:up).permit(productplan_ids: [])
=> {"productplan_ids"=>["", "4"]}
您可以看到 productplan_ids
方法返回 hash
(好吧,不完全是,但现在已经足够接近了)。但是,您需要 :productplan_ids
键的值。所以,试试:
def productplan_ids
params.require(:up)[:productplan_ids]
end
哪个应该给你:
> params.require(:up)[:productplan_ids]
=> ["", "4"]
您正在寻找的 array
。
原始答案
我打算尝试一下,但这会很艰难。
好吧,让我们假设:
- 您有一个登录用户可以通过
current_user
在您的 create
操作中使用(看起来您正在使用 Devise?)
- 您已经创建了
ProductPlans
- 在
routes.rb
中,你有 resources :user_products
(不是 userproducts
,请参阅稍后的注释...)
您的 form_for
应如下所示:
<%= form_for :user_product, user_products_path do |f| %>
<%= f.collection_check_boxes :product_plan_ids, ProductPlan.all, :id, :product_plan_name %>
<%= f.submit %>
<% end %>
注意:您可以使用符号 :user_product
而不是实例变量 @user
因为您没有将任何表单字段基于 @user
.
注意:表单会自动执行 post
,因此您无需指定 method
。
然后,UserProductsController
(不是 ProductPlanController
,因为你要创建一个或多个 user_products
而不是 product_plans
)应该类似于:
class UserProductsController < ApplicationController
def create
current_user.product_plans << ProductPlan.where(id: product_plan_ids)
render action: some_success_condition ? 'index' : 'new'
end
private
def product_plan_ids
params.require(:user_product).permit(product_plan_ids: [])
end
end
注意:您可能不需要 new
操作,因为您实际上不需要实例化任何东西(至少不需要基于您展示的任何东西)。
注意:您需要弄清楚 some_success_condition
是什么。但肯定不是@user.save
。因为您正在创建 user_products
,而不是 user
。
此外,您说:
params.require(:user).permit(:productplan_ids => [])
但是你的参数是:
{
...,
"user"=> {
"productsku_ids"=>["", "4", "7"]
},
"commit"=>"Create User"
}
您允许 productplan_ids
(应该是 product_plan_ids
),但是在您的参数中有 productsku_ids
(应该是 product_sku_ids
)。
其他一些事情:
您应该通读 ruby style guide 以确保您的命名正确。
Class 名称应该是 CamelCase。所以,ProductPlan
,而不是 Productplan
。
符号和变量应该是 SnakeCase。所以,:user_products,而不是 :userproducts.
如果控制器名称是面向资源的,则它们应该是复数,而不是单数。所以,ProductPlansController
,而不是 ProductPlanController
。 (我假设你有 ProductPlan
的所有常用 RESTful 操作,例如 new
、create
、edit
、update
等)
并且,现在 through: :user_products
比 :through => :user_products
更传统。
所以:
class User < ActiveRecord::Base
has_many :user_products
has_many :product_plans, through: :user_products
end
class ProductPlan < ApplicationRecord
has_many :user_products
has_many :users, through: :user_products
end
class UserProduct < ApplicationRecord
belongs_to :user
belongs_to :product_plan
end
此外,您有一堆不匹配的 def ... end
语句:
class ProductPlanController < ApplicationController
before_action :authenticate_user!
def new
@user=User.new
end
end # <= extra 'end' here
def create
@user = User.create(user_params)
if @user.save
render :action => 'index'
else
render :action =>'new'
end
# <= missing 'end' here
private
def user_params
params.require(:user).permit(:productplan_ids => [])
end
end
我认为这是某种复制粘贴错误
我不知道你为什么这样做:
def create
@user = User.create(user_params)
if @user.save
render :action => 'index'
else
render :action =>'new'
end
end
在你的 ProductPlansController
中。是 ProductPlansController
。它应该创建 ProductPlan
,而不是 User
。
请放轻松,因为我只是一个初学者,在过去的两天里,我一直在为这个问题伤脑筋。总而言之,我有一个 user 和 productplan ,当用户选择某个产品计划(单选按钮或复选框)时,我希望将当前用户 ID 和所选产品 ID 存储在名为 userproducts 的连接 table 中 但由于某种原因我无法存储数据,我不知道我哪里出错了,感谢任何帮助,谢谢。
型号:
class User < ActiveRecord::Base
has_many :userproducts
has_many :productplans, :through=>:userproducts
end
class productplan < ApplicationRecord
has_many :userproducts
has_many :users, :through => :userproducts
end
class Userproduct < ApplicationRecord
belongs_to :user
belongs_to :productplan
end
ProductPlan 控制器:
class ProductPlanController < ApplicationController
before_action :authenticate_user!
def new
@user=User.new
end
end
def create
@user = User.create(user_params)
if @user.save
render :action => 'index'
else
render :action =>'new'
end
private
def user_params
params.require(:user).permit(:productplan_ids => [])
end
end
观看次数: productplan/_form.html.erb
<%= form_for @user,:url=> productplan_index_path,:method => :post do
|f|%>
<%= f.collection_check_boxes :productplan_ids, ProductPlan.all, :id,
:productplan_name %>
<%= f.submit %>
<% end %>
由于控制器上的示例和关于 has_many 的视图较少,我很确定我在其中有很多错误。另外,当我尝试提交表单时,我得到了这个日志:
enterStarted POST "/Productplan" for 127.0.0.1 at 2017-11-28 11:08:29 -0600
Processing by ProductPlanController#create as HTML
Parameters
{"utf8"=>"✓","authenticity_token"=>
"mi9RwHCLPKItXai67t5iX0RYrDoE6TN9T
iZzJFYELbKVDlHbhpeNmOC0q2gu1iXyWNaUqGSEsPrBEjcUSE2yYw==", "user"= >
{"productsku_ids"=>["", "4", "7"]}, "commit"=>"Create User"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" =
ORDER BY "users"."id" ASC LIMIT [["id", 3], ["LIMIT", 1]]
ProductPlan Load (2.6ms) SELECT "productplans".* FROM "productplans" WHERE
"productplans"."id" IN (4, 7)
(0.5ms) BEGIN
Provider Load (0.5ms) SELECT "providers".* FROM "providers" WHERE
"providers"."id" = LIMIT [["id", 1], ["LIMIT", 1]]
CACHE Provider Load (0.0ms) SELECT "providers".* FROM "providers" WHERE
"providers"."id" = LIMIT [["id", 1], ["LIMIT", 1]]
(0.6ms) ROLLBACK
Rendering ups/new.html.erb within layouts/application
ProductPlan Load (0.9ms) SELECT "productplans".* FROM "productplans"
Rendered productplans/_form.html.erb (4.6ms)
Rendered productplans/new.html.erb within layouts/application (6.4ms)
Rendered _navbar.html.erb (0.7ms)
Completed 200 OK in 191ms (Views: 102.1ms | ActiveRecord: 14.6ms) here
由于某种原因它回滚了,我也需要获取当前用户。
dependent_new GET /dependent/new(.:format) dependent#new
dependent_create GET /dependent/create(.:format) dependent#create
summary_root GET /summary/index(.:format) summary#index
home_plans GET /home/plans(.:format) home#plans
thanks GET /thanks(.:format) charges#thanks
authenticated_root GET / home#roothome
productplan_index GET /productplan(.:format) productplan#index
POST /productplan(.:format) productplan#create
new_productplan GET /productplan/new(.:format) productplan#new
edit_productplan GET /productplan/:id/edit(.:format) productplan#edit
productplan GET /productplan/:id(.:format) productplan#show
PATCH /productplan/:id(.:format) productplan#update
PUT /productplan/:id(.:format) productplan#update
DELETE /productplan/:id(.:format) productplan#destroy
userproducts GET /userproducts(.:format) userproducts#index
POST /userproducts(.:format) userproducts#create
new_userproduct GET /userproducts/new(.:format) userproducts#new
edit_userproduct GET /userproducts/:id/edit(.:format) userproducts#edit
userproduct GET /userproducts/:id(.:format) userproducts#show
PATCH /userproducts/:id(.:format) userproducts#update
PUT /userproducts/:id(.:format) userproducts#update
DELETE /userproducts/:id(.:format) userproducts#destroy
ups POST /ups(.:format) ups#create
new_up GET /ups/new(.:format) ups#new
root GET / home#index
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
所以我按照@jvillian 的要求修改了我的代码,但问题仍然存在,这是我的新代码。 请注意我将用户产品重命名为 ups,
型号:
class User < ActiveRecord::Base
has_many :ups
has_many :productplans, through: :ups
end
class productplan < ApplicationRecord
has_many :ups
has_many :users, :through => :ups
end
class Up < ApplicationRecord
belongs_to :user
belongs_to :productplan
end
Ups 控制器:
class UpsController < ApplicationController
before_action :authenticate_user!
def create
current_user.productplans<<Productplan.where(id: productplans_ids)
render :action => 'index'
end
private
def productplan_ids
params.require(:up).permit(productplan_ids:[])
end
end
观看次数ups/_form.html.erb
<%= form_for :up,:url=> ups_path do |f| %>
<%= f.collection_check_boxes :productplan_ids, Productplan.all, :id,
:productplan_name %>
<%= f.submit %>
<% end %>
日志:
Started GET "/ups" for 127.0.0.1 at 2017-11-28 14:43:50 -0600
Processing by UpsController#index as HTML
User Load (1.6ms) SELECT "users".* FROM "users" WHERE "users"."id" =
ORDER BY "users"."id" ASC LIMIT [["id", 3], ["LIMIT", 1]]
Rendering ups/index.html.erb within layouts/application
Productplan Load (0.7ms) SELECT "productplans".* FROM "productplans"
Rendered ups/_form.html.erb (42.5ms)
Rendered ups/index.html.erb within layouts/application (47.7ms)
Rendered _navbar.html.erb (0.9ms)
Completed 200 OK in 347ms (Views: 235.0ms | ActiveRecord: 15.0ms)
Started POST "/ups" for 127.0.0.1 at 2017-11-28 14:43:53 -0600
Processing by UpsController#create as HTML
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"g7lLydleU7J14G7N9avWSK87E4BbkPQ9sdL
Q9X2bbSCMmEvSL0LiiLgJbR81o5Hls7UrEjv9d7o+5pTFY9Ly8Q==", "up"=>
{"productplan_ids"=>["", "4"]}, "commit"=>"Save Up"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" =
ORDER BY "users"."id" ASC LIMIT [["id", 3], ["LIMIT", 1]]
Productplan Load (0.7ms) SELECT "productplans".* FROM "productplans" WHERE
"productplans"."id" = [["id", nil]]
(0.4ms) BEGIN
(0.3ms) COMMIT
Rendering ups/index.html.erb within layouts/application
Productplan Load (0.6ms) SELECT "productplans".* FROM "productplans"
Rendered ups/_form.html.erb (4.9ms)
Rendered ups/index.html.erb within layouts/application (7.9ms)
Rendered _navbar.html.erb (1.0ms)
Completed 200 OK in 201ms (Views: 183.4ms | ActiveRecord: 3.0ms)
route.rb
devise_scope :user do
# write all your routes inside this block
resources :productplan
resources :ups
end
Ups中仍然没有插入数据table,也没有报错。虽然根据日志文件它没有回滚,但问题仍然存在。
更新:从 OP
修改代码后更近了!
如您所见:
Productplan Load (0.7ms) SELECT "productplans".* FROM "productplans" WHERE "productplans"."id" = [["id", nil]]
我们没有得到 productplan_ids
完全正确(如 nil
所示)。如果您在控制台中执行以下操作:
> params = ActionController::Parameters.new(up: {productplan_ids: ["","4"]})
> params.require(:up).permit(productplan_ids: [])
=> {"productplan_ids"=>["", "4"]}
您可以看到 productplan_ids
方法返回 hash
(好吧,不完全是,但现在已经足够接近了)。但是,您需要 :productplan_ids
键的值。所以,试试:
def productplan_ids
params.require(:up)[:productplan_ids]
end
哪个应该给你:
> params.require(:up)[:productplan_ids]
=> ["", "4"]
您正在寻找的 array
。
原始答案
我打算尝试一下,但这会很艰难。
好吧,让我们假设:
- 您有一个登录用户可以通过
current_user
在您的create
操作中使用(看起来您正在使用 Devise?) - 您已经创建了
ProductPlans
- 在
routes.rb
中,你有resources :user_products
(不是userproducts
,请参阅稍后的注释...)
您的 form_for
应如下所示:
<%= form_for :user_product, user_products_path do |f| %>
<%= f.collection_check_boxes :product_plan_ids, ProductPlan.all, :id, :product_plan_name %>
<%= f.submit %>
<% end %>
注意:您可以使用符号 :user_product
而不是实例变量 @user
因为您没有将任何表单字段基于 @user
.
注意:表单会自动执行 post
,因此您无需指定 method
。
然后,UserProductsController
(不是 ProductPlanController
,因为你要创建一个或多个 user_products
而不是 product_plans
)应该类似于:
class UserProductsController < ApplicationController
def create
current_user.product_plans << ProductPlan.where(id: product_plan_ids)
render action: some_success_condition ? 'index' : 'new'
end
private
def product_plan_ids
params.require(:user_product).permit(product_plan_ids: [])
end
end
注意:您可能不需要 new
操作,因为您实际上不需要实例化任何东西(至少不需要基于您展示的任何东西)。
注意:您需要弄清楚 some_success_condition
是什么。但肯定不是@user.save
。因为您正在创建 user_products
,而不是 user
。
此外,您说:
params.require(:user).permit(:productplan_ids => [])
但是你的参数是:
{
...,
"user"=> {
"productsku_ids"=>["", "4", "7"]
},
"commit"=>"Create User"
}
您允许 productplan_ids
(应该是 product_plan_ids
),但是在您的参数中有 productsku_ids
(应该是 product_sku_ids
)。
其他一些事情:
您应该通读 ruby style guide 以确保您的命名正确。
Class 名称应该是 CamelCase。所以,ProductPlan
,而不是 Productplan
。
符号和变量应该是 SnakeCase。所以,:user_products,而不是 :userproducts.
如果控制器名称是面向资源的,则它们应该是复数,而不是单数。所以,ProductPlansController
,而不是 ProductPlanController
。 (我假设你有 ProductPlan
的所有常用 RESTful 操作,例如 new
、create
、edit
、update
等)
并且,现在 through: :user_products
比 :through => :user_products
更传统。
所以:
class User < ActiveRecord::Base
has_many :user_products
has_many :product_plans, through: :user_products
end
class ProductPlan < ApplicationRecord
has_many :user_products
has_many :users, through: :user_products
end
class UserProduct < ApplicationRecord
belongs_to :user
belongs_to :product_plan
end
此外,您有一堆不匹配的 def ... end
语句:
class ProductPlanController < ApplicationController
before_action :authenticate_user!
def new
@user=User.new
end
end # <= extra 'end' here
def create
@user = User.create(user_params)
if @user.save
render :action => 'index'
else
render :action =>'new'
end
# <= missing 'end' here
private
def user_params
params.require(:user).permit(:productplan_ids => [])
end
end
我认为这是某种复制粘贴错误
我不知道你为什么这样做:
def create
@user = User.create(user_params)
if @user.save
render :action => 'index'
else
render :action =>'new'
end
end
在你的 ProductPlansController
中。是 ProductPlansController
。它应该创建 ProductPlan
,而不是 User
。