Как сократить тройной запрос ActiveRecord Joins с помощью отношения has_many?

0

Я пытаюсь очистить очень длинный запрос ActiveRecord. У меня есть работа, хотя мне больно смотреть на нее. Вот что происходит.

1) User has_many Simulations через UserSimulations (и наоборот).

2) User Groups через UserGroups (и наоборот).

3) Group has_many Simulations помощью SimulationGroups (и наоборот).

Что здесь происходит, так это то, что пользователь может быть связан с Simulation двумя способами, либо напрямую через has_many, либо с has_many отношениями, или косвенно через Group, к которой принадлежит пользователь.

Я смог собрать все Simulations к которым пользователь имеет доступ в одном запросе, и выглядит так. У меня есть доступ к объекту 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

Я рад, что он работает, но хотел бы очистить его, чтобы быть более кратким (а не 4 строки кода для создания одного запроса).

ОБНОВИТЬ

Здесь представлены модели.

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

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

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
Теги:
activerecord
ruby-on-rails-3

1 ответ

0

Как насчет этого?

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 (пользователь).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))" 
  • 0
    Это работает довольно хорошо. Спасибо Марчелло!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню