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.

Association proxies using class methods with named scopes

#1677

I believe this occurs in both 2.0 and 2.2.

When you attempt to chain named_scopes together in a class method, and then call that class method through an association proxy, the conditions from the association proxy are not applied unless the class method ends with a call to #all when using the named scopes. Simple example follows...

Class definitions...



  class Event

    belongs_to :hub

    def self.upcoming_with_all(limit = nil)
      public.ending_after(Time.now.utc).published.limited(limit).ordered.all
    end

    def self.upcoming_without_all(limit = nil)
      public.ending_after(Time.now.utc).published.limited(limit).ordered
    end
  
  end

  class Hub
    has_many :events
  end

Console output...



  >> Hub.first.events.upcoming_with_all(2)
    Hub Load (0.7ms)   SELECT * FROM `hubs` LIMIT 1
    Event Load (1.0ms)   SELECT * FROM `events` WHERE ((((`events`.hub_id = 1) 
    AND (events.published = 1)) AND (events.ends_at > '2008-12-29 21:17:50')) 
    AND ((not events.private))) ORDER BY events.created_on desc LIMIT 2

  >> Hub.first.events.upcoming_without_all(2)
    Hub Load (0.3ms)   SELECT * FROM `hubs` LIMIT 1
    SQL (345.4ms)   SELECT count(*) AS count_all FROM `events` 
    WHERE (((events.published = 1) AND (events.ends_at > '2008-12-29 21:17:55')) 
    AND ((not events.private))) LIMIT 2

Note how the first version, whose class method has an #all call on the end of the scope chain, correctly uses the condition that comes from the association (ie, it limits to a certain hub), but the second version does not.

Reported by Matt Jankowski · December 31st, 2008 @ 03:54 PM

State: resolved
Milestone: 2.x
Assigned to: nobody
Importance: none

Activity

  1. Frederick Cheung
    Frederick Cheung

    I think I understand why this is. I setup User has_many posts, post has a named_scope called active.

    When you do

    
    User.last.posts.active
    

    Then active is called on the association proxy, and method missing on the association proxy knows that if you call :foo on it and :foo is a named scope on the parent then it should call that scope on itself (ie the named scope is called with proxy_scope set to the association proxy)

    When you do

    
    class Post
      def self.class_method
        active
      end
    end
    User.last.posts.class_method
    

    Then the active method is called on class Post, not the association proxy and so the named scope is called with proxy_scope set to Post, not the association proxy.

    The association proxy wraps the call to class_method in a with_scope with the conditions so if class_method does a find then it will execute inside the with_scope block and everything is fine. But if it just invokes a scope upon which a find is done later then that find is executed outside the with_scope and so everything falls to pieces.

    December 31st, 2008 @ 05:00 PM

  2. Diego Algorta
    Diego Algorta

    I think my patch on #1960 fixes this.

    February 20th, 2009 @ 01:56 PM

  3. Repository
    Repository
    • State changed from new to resolved

    (from [a9aa18fdcdf3146ccbdecff71e52015f26a0f0b7]) Fixed bug that makes named_scopes forgot current scope

    Signed-off-by: rick technoweenie@gmail.com [#1960 #1677 state:resolved] http://github.com/rails/rails/co...

    February 25th, 2009 @ 05:13 PM