简体   繁体   English

Rails has_many和has_one与参数

[英]Rails has_many and has_one with argument

I have a setup like the below: 我有如下设置:

user.rb user.rb

class User < ActiveRecord::Base
  ...

  has_many :projects_users
  has_many :projects, through: :projects_users  

  ...

end

projects_users.rb projects_users.rb

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

  has_one :projects_users_role  
end

project.rb project.rb

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

Users are nested under Project in my routes file. 用户嵌套在我的路线文件中的Project下。

For some reason, I cannot seem to find a good way of accessing a single project for a user. 由于某种原因,我似乎找不到为用户访问单个项目的好方法。 Ideally I would like to create a 理想情况下,我想创建一个

 has_one :project_user

association and then a 关联,然后

has_one :project, through: :project_user 

and somehow pass and id for the project to the association (which I know is not possible). 并以某种方式将项目的ID和ID传递给关联(我知道这是不可能的)。 Any ideas for a good approach. 任何好的方法的想法。

I would then like to call a method similar to 然后,我想调用类似于

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

in my users controller. 在我的用户控制器中。

Any assistance is greatly appreciated. 非常感谢您的协助。

Thank you 谢谢

UPDATE UPDATE

I essentially have a role that is attached per project per user in the projects_users.rb (updated above and added below) 我本质上是在projects_users.rb中为每个用户的每个项目附加了一个角色(上面已更新,下面已添加)

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 projects_users_role.rb

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

And my aim, which I should have stated previously is to be able to edit this role for the user on the given project via a route like 我的目标(我之前应该已经说过)是能够通过类似以下路线为给定项目中的用户编辑此角色

  /projects/1/users/2/edit-roles

this would display the user, and allow me to assign the role to the projects_users_roles table, with the nested ids added ie the id from the project_users table. 这将显示用户,并允许我将角色分配给projects_users_roles表,并添加嵌套的ID,即project_users表中的ID。 Hence I would like (I think) to have a has_one to projects with an argument so that my nested form would be simpler. 因此,我希望(我认为)使用一个参数将has_one投影到项目中,以便嵌套形式更简单。

Update 2 更新2

I have stumbled across this 我偶然发现了这个

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

from here http://www.rojotek.com/blog/2014/05/16/cool-stuff-you-can-do-with-rails-has_one/ but cannot make it apply as replacing 'department' with 'project' does not use the project id in the join but the user id in my case. 从这里http://www.rojotek.com/blog/2014/05/16/cool-stuff-you-can-do-with-rails-has_one/,但是不能以将“部门”替换为“项目”来应用在联接中不使用项目ID,但在本例中为用户ID。

user.rb update user.rb 更新

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

From the console 从控制台

 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

The project_id should be 1 in this case but it is using the user.id 26. Not sure why really. 在这种情况下,project_id应该为1,但它正在使用user.id26。不确定为什么。

Thanks again 再次感谢

That is correct, if you have a model User , an argument which is passed to closure is the self for called class instance, ie it will be an instance of User . 没错,如果您有模型User ,则传递给闭包的参数是被调用类实例的self ,即它将是User的实例。 So in following code piece project variable will have a user value. 因此,在以下代码段中, project变量将具有user值。

user.rb user.rb

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

To pass into has_many/one relation an additional argument use extending selector: 要将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)

The approach is described in Association Extension head in Rails Association page. 该方法在Rails Association页面的Association Extension头中进行了描述。

One of various ways to produce your result in one SQL statement, would be with a left join: 在一个SQL语句中产生结果的多种方法之一是左连接:

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

UPDATE UPDATE
The above statement will produce an extra SQL request if you want to get: 如果您希望获得上述声明,则会产生一个额外的SQL请求:

@user.projects.first.id

If you want no more statements for the project (of course you don't) you should combine the join with an include: 如果您不希望该项目有更多的语句(当然,您不希望这样做),则应将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

So now 所以现在

@user.projects.first.id

will produce no extra SQL statements 不会产生额外的SQL语句

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM