自加入HABTM协会的范围

Posted

技术标签:

【中文标题】自加入HABTM协会的范围【英文标题】:Scope for Self-joining HABTM Association 【发布时间】:2012-01-20 01:30:12 【问题描述】:

Ruby 1.9.2 上使用Rails 3.1.3,我有:

class User < ActiveRecord::Base
  has_and_belongs_to_many :states
end

class State < ActiveRecord::Base
  has_and_belongs_to_many :users
end

User 与许多 States 相关联,State 与许多 Users 相关联。给定一个User,我想找到在她的任何州的所有其他Users。

我试过了:

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

想法?

谢谢。

更新 12/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)

它不是特别优雅,但它正在工作。您必须为“传入”User 引用 users 引用别名,以便您可以将此范围与其他范围链接,例如:

scope :active, where(active => true)

User.in_states_of(current_user).active

欢迎提出任何改进建议。

【问题讨论】:

【参考方案1】:

这是有效的:

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)

它不是特别优雅,但它正在工作。您必须为“传入”User 引用 users 别名,以便您可以将此范围与其他范围链接,例如:

scope :active, where(active => true)

User.in_states_of(current_user).active

欢迎提出任何改进建议。

【讨论】:

以上是关于自加入HABTM协会的范围的主要内容,如果未能解决你的问题,请参考以下文章

顶象受邀加入深圳市网络与信息安全协会

深擎科技携手上海市人工智能技术协会共谋发展

Ruby on rails 协会 - 用户(设计)在注册和登录后可以“创建团队”或“加入团队”

共推体验数智化 大树体验云加入UXPA中国用户体验专业协会

[航海协会]树

[航海协会]树