This project is archived and is in readonly mode.

#1226 ✓resolved
Jérôme

named_scope buggy with has_many :through

Reported by Jérôme | October 16th, 2008 @ 01:27 PM | in 2.x

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,... >]

Comments and changes to this ticket

  • Frederick Cheung

    Frederick Cheung December 21st, 2008 @ 10:49 PM

    • 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)

  • Dennis Ushakov

    Dennis Ushakov January 16th, 2009 @ 01:31 PM

    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

  • Dennis Ushakov

    Dennis Ushakov January 16th, 2009 @ 01:38 PM

    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"
    
    
  • Prem Sichanugrist (sikachu)

    Prem Sichanugrist (sikachu) January 22nd, 2010 @ 08:52 AM

    • State changed from “incomplete” to “resolved”

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages