Note that there are some explanatory texts on larger screens.

plurals
  1. POScope for Self-joining HABTM Association
    primarykey
    data
    text
    <p>With <code>Rails 3.1.3</code> on <code>Ruby 1.9.2</code>, I have:</p> <pre><code>class User &lt; ActiveRecord::Base has_and_belongs_to_many :states end class State &lt; ActiveRecord::Base has_and_belongs_to_many :users end </code></pre> <p>A <code>User</code> is associated with many <code>State</code>s, and a <code>State</code> with many <code>User</code>s. Given a <code>User</code>, I want to find all other <code>User</code>s who are in any of her states.</p> <p>I tried:</p> <pre><code>class User &lt; ActiveRecord::Base scope :in_state, lambda { |states| joins(:states).where(:states =&gt; states) } end User.in_state(current_user.states).all </code></pre> <p>With this error (formatted for readability):</p> <pre><code>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) </code></pre> <p>I realize I need some way to alias one of the <code>states_users</code> references, but I'm at a loss for figuring out how to do this with <a href="http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html#method-i-scope" rel="nofollow"><code>scope</code></a>.</p> <p>Here's the SQL I would write:</p> <pre><code>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 </code></pre> <p>Thoughts?</p> <p>Thanks.</p> <p><strong>UPDATE 12/14/2011 @ 10:48 AM:</strong></p> <p>Here's what's working:</p> <pre><code>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) </code></pre> <p>It's not particularly elegant, but it's working. You have to alias the <code>users</code> reference for the "incoming" <code>User</code> so you can chain this scope with others, such as:</p> <pre><code>scope :active, where(active =&gt; true) User.in_states_of(current_user).active </code></pre> <p>Any suggestions for improvement would be most welcome.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload