【问题标题】:Rails has_many and has_one with argumentRails has_many 和 has_one 带参数
【发布时间】:2015-05-09 20:58:31
【问题描述】:

我有如下设置:

用户.rb

class User < ActiveRecord::Base
  ...

  has_many :projects_users
  has_many :projects, through: :projects_users  

  ...

end

projects_users.rb

class ProjectsUser < ActiveRecord::Base
  belongs_to :project
  belongs_to :user

  has_one :projects_users_role  
end

项目.rb

class Project < ActiveRecord::Base
  has_many :projects_users
  has_many :users, through: :projects_users
end

用户嵌套在我的路由文件中的项目下。

出于某种原因,我似乎找不到为用户访问单个项目的好方法。理想情况下,我想创建一个

 has_one :project_user

联想,然后是一个

has_one :project, through: :project_user 

并以某种方式将项目的 ID 传递给关联(我知道这是不可能的)。任何关于好方法的想法。

然后我想调用一个类似的方法

   @user = User.includes(:project (project_id parameter).find(:id) 

在我的用户控制器中。

非常感谢任何帮助。

谢谢

更新

我基本上在 projects_users.rb 中为每个用户的每个项目附加了一个角色(在上面更新并在下面添加)

projects_users.rb

class ProjectsUser < ActiveRecord::Base
  belongs_to :project
  belongs_to :user

  has_one :projects_users_role  
end

projects_users_role.rb

  class ProjectsUsersRole < ActiveRecord::Base
    belongs_to :projects_user
    enum role: [...]
  end

我的目标,我之前应该说过的,是能够通过像

这样的路径为给定项目中的用户编辑这个角色
  /projects/1/users/2/edit-roles

这将显示用户,并允许我将角色分配给 projects_users_roles 表,并添加嵌套 id,即 project_users 表中的 id。因此,我希望(我认为)对带有参数的项目有一个 has_one,这样我的嵌套形式会更简单。

更新 2

我偶然发现了这个

 has_one :project_department, ->(department) { where department: department }, class_name: 'ProjectDepartment'  

从这里http://www.rojotek.com/blog/2014/05/16/cool-stuff-you-can-do-with-rails-has_one/ 但不能使其适用,因为用“项目”替换“部门”不使用连接中的项目 ID,但在我的情况下使用用户 ID。

user.rb 更新

...
has_one :project_user, -> (project) { where project: project},    class_name: 'ProjectsUser'
has_one :project, through: :project_user  
...

从控制台

 User.first.project_user(1)
  User Load (0.2ms)  SELECT  `users`.* FROM `users`  ORDER BY `users`.`id` ASC LIMIT 1
  ProjectsUser Load (0.1ms)  SELECT  `projects_users`.* FROM `projects_users` WHERE `projects_users`.`user_id` = 26 AND `projects_users`.`project_id` = 26 LIMIT 1

在这种情况下,project_id 应该是 1,但它使用的是 user.id 26。不知道为什么。

再次感谢

【问题讨论】:

  • 现在的方式,@user.projects.find(:id) 应该可以工作,如果我得到正确的图片,id 是项目的 id。
  • 我当时的路线是 /projects/1/user/2 ,其中 1 是 project_id 参数,2 是 user.id 参数。您是否建议执行 2 行语句,例如 user = User.find(:id) 然后 @project = user.projects.find(:project_id)。这会产生 2 个查询还是足够聪明只做 1 个?谢谢
  • 这将生成两个查询。所以会写User.find(:id).projects.find(:project_id)。使用单个 SQL 语句的一种方法是我在下面提供的答案。
  • 这很棒,而且会在一定程度上发挥作用。我也许应该更清楚。请看更新
  • 感谢您的头痛。我现在不能帮你解决这个问题,但我认为这个想法不会有太大的不同,扩大一点。

标签: ruby-on-rails associations has-many has-one


【解决方案1】:

没错,如果你有一个模型User,传递给闭包的参数是被调用类实例的self,即它将是User的一个实例。所以在下面的代码片段中project 变量将有一个user 值。

user.rb

has_one :project_user, -> (project) { where project: project}, class_name: 'ProjectsUser'

要将附加参数传递给has_many/one 关系,请使用扩展选择器:

class User < ActiveRecord::Base
   has_one :project_user, class_name: 'ProjectsUser' do
      def for_project(project)
         where(project: project)
      end
   end
end

customers.project_user.for_project(project)

Rails Association 页面中的 Association Extension head 中描述了该方法。

【讨论】:

    【解决方案2】:

    在一条 SQL 语句中生成结果的多种方法之一是使用左连接:

    @user=User.joins(:projects).
         where("users.id = ? and projects.id = ?", 
                params[:id], 
                params[:project_id]).take # use take to get one row only
    

    更新
    如果你想获取,上面的语句会产生一个额外的 SQL 请求:

    @user.projects.first.id
    

    如果您不希望项目有更多语句(当然您不希望),您应该将 join 与 include 结合起来:

    @user=User.joins(:projects).includes(:projects).
         where("users.id = ? and projects.id = ?", 
                params[:id], 
                params[:project_id]).take # use take to get one row only
    

    现在

    @user.projects.first.id
    

    不会产生额外的 SQL 语句

    【讨论】:

      猜你喜欢
      • 2018-04-08
      • 2019-03-04
      • 1970-01-01
      • 1970-01-01
      • 2012-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多