Scope for Self-joining HABTM Association

☆樱花仙子☆ 提交于 2019-12-12 03:22:01

问题


With Rails 3.1.3 on Ruby 1.9.2, I have:

class User < ActiveRecord::Base
  has_and_belongs_to_many :states
end

class State < ActiveRecord::Base
  has_and_belongs_to_many :users
end

A User is associated with many States, and a State with many Users. Given a User, I want to find all other Users who are in any of her states.

I tried:

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

User.in_state(current_user.states).all

With this error (formatted for readability):

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)

I realize I need some way to alias one of the states_users references, but I'm at a loss for figuring out how to do this with scope.

Here's the SQL I would write:

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

Thoughts?

Thanks.

UPDATE 12/14/2011 @ 10:48 AM:

Here's what's working:

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)

It's not particularly elegant, but it's working. You have to alias the users reference for the "incoming" User so you can chain this scope with others, such as:

scope :active, where(active => true)

User.in_states_of(current_user).active

Any suggestions for improvement would be most welcome.


回答1:


Here's what's working:

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)

It's not particularly elegant, but it's working. You have to alias the users reference for the "incoming" User so you can chain this scope with others, such as:

scope :active, where(active => true)

User.in_states_of(current_user).active

Any suggestions for improvement would be most welcome.



来源:https://stackoverflow.com/questions/8501687/scope-for-self-joining-habtm-association

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!