Возможности для самостоятельного присоединения к ассоциации HABTM - PullRequest
0 голосов
/ 14 декабря 2011

С Rails 3.1.3 на Ruby 1.9.2, у меня есть:

class User < ActiveRecord::Base
  has_and_belongs_to_many :states
end

class State < ActiveRecord::Base
  has_and_belongs_to_many :users
end

A User ассоциируется со многими State с, а State со многими User с. Учитывая User, я хочу найти всех других User, которые находятся в любом из ее состояний.

Я пытался:

class User < ActiveRecord::Base
  scope :in_state, lambda { |states| joins(:states).where(:states => states) }
end

User.in_state(current_user.states).all

С этой ошибкой (отформатированной для удобства чтения):

Mysql2::Error: Not unique table/alias: 'states_users': 
SELECT COUNT(*) 
FROM `users` 
  INNER JOIN `states_users` ON `states_users`.`user_id` = `users`.`id` 
  INNER JOIN `states` ON `states`.`id` = `states_users`.`state_id` 
  LEFT OUTER JOIN states_users on users.id = states_users.user_id AND states_users.state_id IS NULL 
WHERE `states`.`id` IN (8)

Я понимаю, что мне нужен какой-то способ для псевдонима одной из states_users ссылок, но я не могу понять, как это сделать с scope.

Вот SQL, который я бы написал:

SELECT u2.*
FROM users u
  INNER JOIN states_users su ON su.user_id = u.id
  INNER JOIN states s ON s.id = su.state_id
  INNER JOIN states_users su2 ON s.id = su2.state_id
  INNER JOIN users u2 ON u2.id = su2.user_id
WHERE u.id = 771

Мысли

Спасибо.

ОБНОВЛЕНИЕ 14/14/2011 @ 10:48 AM:

Вот что работает:

scope :in_states_of, lambda { |user|
  joins('INNER JOIN states_users su ON su.user_id = users.id ' +
        'INNER JOIN states s ON s.id = su.state_id '           +
        'INNER JOIN states_users su2 ON s.id = su2.state_id '  +
        'INNER JOIN users u ON u.id = su2.user_id').
  where("u.id = ?", user.id) }

User.in_states_of(current_user)

Это не особо элегантно, но работает. Вам необходимо присвоить псевдоним users для «входящих» User, чтобы вы могли связать эту область с другими, такими как:

scope :active, where(active => true)

User.in_states_of(current_user).active

Любые предложения по улучшению приветствуются.

1 Ответ

0 голосов
/ 11 сентября 2012

Вот что работает:

scope :in_states_of, lambda { |user|
  joins('INNER JOIN states_users su ON su.user_id = users.id ' +
        'INNER JOIN states s ON s.id = su.state_id '           +
        'INNER JOIN states_users su2 ON s.id = su2.state_id '  +
        'INNER JOIN users u ON u.id = su2.user_id').
  where("u.id = ?", user.id) }

User.in_states_of(current_user)

Это не особенно элегантно, но работает.Вам необходимо присвоить псевдоним users для «входящих» User, чтобы вы могли связать эту область с другими, такими как:

scope :active, where(active => true)

User.in_states_of(current_user).active

Любые предложения по улучшению будут приветствоваться.

...