Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

named_scope buggy with has_many :through

#1226

Hello,

I found named_scope is buggy with has_many :through when the 2 models do have the same column name used by the scope.


class User < AR::Base
  has_many :friendships
  has_many :friends, :class_name => 'User', :through => :friendships
end

class Friendship < AR::Base
  belongs_to :user
  belongs_to :friend, :class_name => 'User', :foreign_key => 'friend_id'

  named_scope :pending,  :conditions => { :state => 'pending' }
  named_scope :accepted, :conditions => { :state => 'accepted' }
  named_scope :denied,   :conditions =>  { :state => 'denied' }
end

>> User.first.friendships.pending
=> []
# SELECT "users".* FROM "users" INNER JOIN friendships ON users.id = friendships.friend_id WHERE (("friendships".user_id = 1)) AND ("users"."state" = E'pending')

See ?

The SQL query takes "users"."state" instead of "friendships"."state".

Now the weirderst part:


class Friendship < AR::Base
  belongs_to :user
  belongs_to :friend, :class_name => 'User', :foreign_key => 'friend_id'

  named_scope :pending,  :conditions => { 'friendships.state' => 'pending' }
  named_scope :accepted, :conditions => { 'friendships.state' => 'accepted' }
  named_scope :denied,   :conditions => { 'friendships.state' => 'denied' }
end

Declaring the table name in the :conditions hash doesn't change anything ! It still queries "users"."state" !

The only way I found to solve this issue is to double the friendships named_scope in the user model !!


class User < ActiveRecord::Base
  has_many :friendships
  has_many :friends, :class_name => 'User', :through => :friendships
  named_scope :pending,  :conditions => { 'friendships.state' => 'pending' }
  named_scope :accepted, :conditions => { 'friendships.state' => 'accepted' }
  named_scope :denied,   :conditions => { 'friendships.state' => 'denied' }
 end

of course the following will raise an error:


>> User.first.pending

but this call won't now:


>> User.first.friends.pending
=> [#<User id: 7701,... >]

Reported by Jérôme · October 16th, 2008 @ 01:27 PM

State: resolved
Milestone: 2.x
Assigned to: Frederick Cheung Frederick Cheung
Importance: none

Activity

  1. Frederick Cheung
    Frederick Cheung
    • Assigned user set to Frederick Cheung
    • State changed from new to incomplete

    I couldn't reproduce this with 2.1.2 or 2.2.2 or edge

    I think you've skipped over a few steps. In the first bit you show a query selecting users.* going wrong but the corresponding bit of code you've shown you should be loading friendships, not users. Could your provide a more complete description of steps to reproduce ? (or even better, a failing test case)

    December 21st, 2008 @ 10:49 PM

  2. Dennis Ushakov
    Dennis Ushakov

    Frederick, actually there's a bug in specification or in reflection code Spec says:

    [:through]

    Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key

    are ignored, as the association uses the source reflection. You can only use a :through query through a belongs_to

    or has_many association on the join model.

    As we see here, :class_name should be ignored.

    But in the source code we see: MacroReflection class in reflection.rb:

    Returns the class name for the macro. For example, composed_of :balance, :class_name => 'Money' returns 'Money'

    and has_many :clients returns 'Client'.

    def class_name @class_name ||= options[:class_name] || derive_class_name end and no check for through attribute

    January 16th, 2009 @ 01:31 PM

  3. Dennis Ushakov
    Dennis Ushakov

    Sorry for formatting issues. One addition. As I understand :source attribute should be used in this case, but it seems typo is dependent on this behaviour: class Category < ActiveRecord::Base acts_as_list has_many :categorizations

    has_many :articles,

    :through => :categorizations,
    :order   => "published_at DESC, created_at DESC"
    
    

    has_many :published_articles,

    :through    => :categorizations,
    :class_name => 'Article',
    :conditions => { :published => true },
    :order      => "published_at DESC"
    
    

    January 16th, 2009 @ 01:38 PM

  4. Prem Sichanugrist (sikachu)
    Prem Sichanugrist (sikachu)
    • State changed from incomplete to resolved

    January 22nd, 2010 @ 08:52 AM