【问题标题】:How to create controller and views for has_many and through relationship in ruby on rails如何在 ruby​​ on rails 中为 has_many 和通过关系创建控制器和视图
【发布时间】:2017-11-28 17:23:55
【问题描述】:

请放轻松,因为我只是一个初学者,在过去的 2 天里,我一直在为这个问题头疼。总而言之,我有一个用户和产品计划,当用户选择某个产品计划(单选按钮或复选框)时,我希望将当前用户 ID 和所选产品 ID 存储在名为 userproducts 的联接表中 但由于某种原因,我无法存储数据,我不知道哪里出错了,感谢任何帮助,谢谢。

型号:

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" = $1 
ORDER BY "users"."id" ASC LIMIT $2  [["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" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
CACHE Provider Load (0.0ms)  SELECT  "providers".* FROM "providers" WHERE 
"providers"."id" = $1 LIMIT $2  [["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" = $1 
ORDER BY "users"."id" ASC LIMIT $2  [["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" = $1 
ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
Productplan Load (0.7ms)  SELECT "productplans".* FROM "productplans" WHERE 
"productplans"."id" = $1  [["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)

路由.rb

devise_scope :user do
# write all your routes inside this block
resources :productplan
resources :ups
end

Ups表中仍然没有插入数据,也没有错误。虽然根据日志文件它没有回滚,但问题仍然存在。

【问题讨论】:

  • 您的 form_for url 似乎不正确&lt;%= form_for @user,:url=&gt; productplan_index_path ,应该是创建操作而不是索引操作
  • 为什么你的 ProductPlanController 有用户资源的方法。它应该是 ProductPlan 的控制器。这对我来说毫无意义
  • 我担心这段代码太坏而无法修复。
  • @xeon131 我使用索引路径,因为通过运行 rake 路由我得到 productplan_index GET /productplan(.:format) productplan#index POST /productplan(.:format) productplan#create
  • @MatiasSeguel 嗨!您是否建议为用户创建一个单独的控制器??

标签: ruby-on-rails ruby has-many-through


【解决方案1】:

更新:从 OP 修改代码后

更近了!

如您所见:

Productplan Load (0.7ms)  SELECT "productplans".* FROM "productplans" WHERE "productplans"."id" = $1  [["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 以确保您的命名正确。

类名应该是 CamelCase。所以,ProductPlan,而不是Productplan

符号和变量应该是 SnakeCase。所以,:user_products,而不是 :userproducts。

控制器名称应该是复数,而不是单数,如果它们是面向资源的。所以,ProductPlansController,而不是ProductPlanController。 (我假设您对ProductPlan 具有所有常用的 RESTful 操作,例如 newcreateeditupdate 等)

而且,现在through: :user_products:through =&gt; :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

【讨论】:

  • 嗨,非常感谢您的帖子,我一定会尝试这个,也仅供参考,我有命名错误,因为我已经从我的原始代码编辑,因为命名很复杂,我不想混淆任何人,例如 ProductPlan 实际上是我原始代码中的 Productsku。但非常感谢,我会尝试这个并回复你。CHeers。
  • 好吧,我按照你说的做了,创建了一个新的控制器并尽可能地清理了代码,但仍然没有在连接表中插入数据。我会尽快发布新代码
  • 我用你的代码更新了帖子,请看一下。谢谢。
  • 我更新了答案(顶部有新内容)。我认为你很接近。
  • OHHH DAMNNN...非常感谢,这很有帮助,我终于可以让它工作了。数据成功存储在表格中。先生,您值得敬礼,让我头疼不已... :-) 再次感谢。干杯。
猜你喜欢
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 2012-06-12
  • 2016-04-14
  • 1970-01-01
  • 2015-02-26
  • 2011-12-28
相关资源
最近更新 更多