简体   繁体   English

如何通过关系通过has_many缩短三联Join ActiveRecord查询?

[英]How do I shorten a triple Joins ActiveRecord Query with a has_many through relations?

I'm trying to clean up a very long ActiveRecord query. 我正在尝试清理很长的ActiveRecord查询。 The one I have is working, though it hurts to look at it. 我的那个正在工作,尽管很难看。 Here's what is happening. 这是正在发生的事情。

1) User has_many Simulations through UserSimulations (and vice versa). 1) User的has_many Simulations通过UserSimulations (反之亦然)。

2) User has_many Groups through UserGroups (and vice versa). 2) User的has_many Groups通过UserGroups (反之亦然)。

3) Group has_many Simulations through SimulationGroups (and vice versa). 3)通过SimulationGroups has_many Simulations Group (反之亦然)。

What ends up happening here is that a user can be associated to a Simulation in two ways, either directly through the has_many to has_many relationship, or indirectly through a Group that the user belongs to. 最终发生的事情是,可以通过两种方式将用户与Simulation关联,或者直接通过has_many到has_many关系,或者间接通过用户所属的Group

I've been able to gather all the Simulations a User has access to in a single query, and it looks like this. 我已经能够在一个查询中收集用户可以访问的所有Simulations ,它看起来像这样。 I have access to the current_user object where the query needs to be called. 我可以访问需要调用查询的current_user对象。

# Define Queries
user_sim_join = "LEFT JOIN user_simulations ON user_simulations.simulation_id = simulations.id"
user_grp_join = "LEFT JOIN user_groups ON user_groups.group_id = groups.id"
where_clause  = ["user_groups.user_id = :user_id OR user_simulations.user_id = :user_id", { user_id: user.id }]

# Run Query
Simulation.joins(user_sim_join, :groups, user_grp_join).where(where_clause).group('simulations.id') 

#=> Simulation Load (1.1ms)  SELECT "simulations".* FROM "simulations" 
         INNER JOIN "simulation_groups" ON "simulation_groups"."simulation_id" = "simulations"."id" 
         INNER JOIN "groups" ON "groups"."id" = "simulation_groups"."group_id" 
         LEFT JOIN user_simulations ON user_simulations.simulation_id = simulations.id 
         LEFT JOIN user_groups ON user_groups.group_id = groups.id 
         WHERE (user_groups.user_id = 2 OR user_simulations.user_id = 2) 
         GROUP BY simulations.id

I'm happy that it's working but would like to clean it up as to be more concise (not 4 lines of code to build a single query). 我很高兴它能正常工作,但想对其进行简化以使其更加简洁(构建单个查询的代码不是4行)。

UPDATE 更新

Here are the models involved. 这是涉及的模型。

Simulation.rb Simulation.rb

class Simulation < ApplicationRecord
  # Associations
  belongs_to :company

  has_many :simulation_groups
  has_many :user_simulations
  has_many :objection_responses

  has_many :groups, through: :simulation_groups
  has_many :users, through: :user_simulations

  has_many :reports, as: :reportable
  has_many :objections, as: :objectionable

  # Validations
end

Group.rb Group.rb

class Group < ApplicationRecord
  belongs_to :company
  has_many :simulation_groups
  has_many :simulations, through: :simulation_groups
  has_many :user_groups
  has_many :users, through: :user_groups
  has_many :minigame_groups
  has_many :minigames, through: :minigame_groups
  has_many :reports, through: :users

  # Validations
end

User.rb User.rb

class User < ApplicationRecord
  # Associations
  belongs_to :company

  has_one  :avatar
  has_many :reports
  has_many :events
  has_many :training_sessions
  has_many :user_groups
  has_many :groups, through: :user_groups
  has_many :objection_responses
  has_many :user_simulations
  has_many :simulations, through: :user_simulations
  has_many :minigame_users
  has_many :minigames, through: :minigame_users

  # Validations
end

What about this? 那这个呢?

scope :from_user, lambda{|user|
  joins('left join user_simulations us ON (us.simulation_id = simulations.id)').
  joins('left join group_simulations gs ON (gs.simulation_id = simulations.id)').
  where("us.user_id = ? OR gs.group_id IN (?)",
        user.id,
        UserGroup.select("group_id").where(user_id: user.id))}

Simulation.from_user(user).to_sql: Simulation.from_user(user).to_sql:

"SELECT `simulations`.* FROM `simulations` 
left join user_simulations us ON (us.simulation_id = simulations.id)
left join group_simulations gs ON (gs.simulation_id = simulations.id) 
WHERE (us.user_id = 1 OR gs.group_id IN (
  SELECT `user_groups`.`group_id` FROM `user_groups` 
  WHERE `user_groups`.`user_id` = 1))" 

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

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