Given these models
class Category < ActiveRecord
has_many :category_assignments
has_many :posts, :through => :category_assignments
end
class CategoryAssignment < ActiveRecord::Base
belongs_to :post
belongs_to :category
# Has boolean column ''featured''
end
class Post < ActiveRecord::Base
has_many :category_assignments
has_many :categories, :through => :category_assignments
end
I want to add a named_scope to Post that will return all featured
posts. But the semantics of this named_scope vary depending upon
whether I am calling the named scope on Post or on category.posts:
Post.featured
is simple enough. The definition
named_scope :featured,
:joins => :category_assignments,
:conditions => {:category_assignments.featured => true }
will return all posts for which any associated category_assignment
record has featured = true.
But when I take a category instance and call category.posts.featured I
want to get all of the posts which are featured *in that category*,
which requires restricting by category_id. To do this properly the
named_scope code needs to be able to determine whether it''s being
called in a context in which category_assignments has already been
joined (and/or whether a category_id is specified in the conditions).
I have not figured out how to do this.
If I can detect whether or not the named_scope is being called within
the context of an association then I can do something like the
following, which changes named_scope semantics based on whether or not
a category _argument_ is explicitly provided:
named_scope :featured, lambda { |*args|
if (category = args.first)
{ :joins => :category_assignments,
:conditions => {:category_id => category.id,
:featured => true} }
else
{ :joins => :category_assignments,
:conditions => {:featured => true} }
end
}
Is there some way to inspect a joins or conditions hash to determine
association state from within a named_scope? And if so, is it reliable
regardless of the order of named_scope stacking (i.e. will it work for
either category.posts.other.named.scopes.featured or
category.posts.featured.other.named.scopes)?
Thanks,
Sven
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Nov-24 17:49 UTC
Re: How to make named_scope aware of association context?
On Nov 24, 5:43 pm, Sven <Sven....-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Given these models > > class Category < ActiveRecord > has_many :category_assignments > has_many :posts, :through => :category_assignments > end > > class CategoryAssignment < ActiveRecord::Base > belongs_to :post > belongs_to :category > # Has boolean column ''featured'' > end > > class Post < ActiveRecord::Base > has_many :category_assignments > has_many :categories, :through => :category_assignments > end > > I want to add a named_scope to Post that will return all featured > posts. But the semantics of this named_scope vary depending upon > whether I am calling the named scope on Post or on category.posts: > Post.featured > is simple enough. The definition > named_scope :featured, > :joins => :category_assignments, > :conditions => {:category_assignments.featured => true } > will return all posts for which any associated category_assignment > record has featured = true. > > But when I take a category instance and call category.posts.featured I > want to get all of the posts which are featured *in that category*, > which requires restricting by category_id. To do this properly theIt should do that by itself. You shouldn''t need to do anything. Have you tried it? Fred --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Mon, Nov 24, 2008 at 12:49 PM, Frederick Cheung < frederick.cheung-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> It should do that by itself. You shouldn''t need to do anything. Have > you tried it? > > Fred >Yes, with code like this: named_scope :featured, :joins => :category_assignments, :conditions => [''category_assignments.featured = ?'', true ] When I call Post.featured it works fine. But when I call, category.posts.featured I get ActiveRecord::StatementInvalid: SQLite3::SQLException: ambiguous column name: category_assignments.post_id because Rails generates this query: SELECT "posts".* FROM "posts" INNER JOIN "category_assignments" ON category_assignments.post_id post.id INNER JOIN category_assignments ON posts.id category_assignments.post_id WHERE (("category_assignments".category_id = 1)) AND ((category_assignments.featured = ''t'')) As you can see, category_assignments is being joined twice. The named_scope needs to omit the category_assignments join when it gets called on a Category instance. I''m running this on Rails 2.1.1, by the way. -Sven PS: there was an error in my initial post. I specified :conditions => {:category_assignments.featured => true } where I ought to have written :conditions => [''category_assignments.featured = ?'', true] --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Nov-24 18:25 UTC
Re: How to make named_scope aware of association context?
On 24 Nov 2008, at 18:07, Sven Aas wrote:> On Mon, Nov 24, 2008 at 12:49 PM, Frederick Cheung <frederick.cheung-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > > wrote: > It should do that by itself. You shouldn''t need to do anything. Have > you tried it? > > Fred > > Yes, with code like this: > > named_scope :featured, :joins => :category_assignments, > :conditions => > [''category_assignments.featured = ?'', true ] > > When I call > > Post.featured > > it works fine. But when I call, category.posts.featured I get > > ActiveRecord::StatementInvalid: SQLite3::SQLException: ambiguous > column name: category_assignments.post_id > > because Rails generates this query: > > SELECT "posts".* FROM "posts" > INNER JOIN "category_assignments" ON category_assignments.post_id > = post.id > INNER JOIN category_assignments ON posts.id = > category_assignments.post_id > WHERE (("category_assignments".category_id = 1)) > AND ((category_assignments.featured = ''t'')) > > As you can see, category_assignments is being joined twice. The > named_scope needs to omit the category_assignments join when it gets > called on a Category instance. >Oops. I skimmed over the definition of your scope and didn''t notice that there was a join. I''m going out on a limb here but from inside a procedural named scope then if there is a @proxy_owner instance variable or if it responds to proxy_owner/proxy_target then it;s an association. You could also check the current scope and see what joins are in there. Fred> I''m running this on Rails 2.1.1, by the way. > > -Sven > > PS: there was an error in my initial post. I specified > :conditions => {:category_assignments.featured => true } > where I ought to have written > :conditions => [''category_assignments.featured = ?'', true] > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
That does seem promising, but I haven''t gotten it to work yet. Both proxy_owner and proxy_target remain undefined (on self) and @proxy_owner remains null regardless of which way I invoke the named_scope lambda. You also suggested checking the current scope for joins but that''s precisely the thing I don''t know how to do, which prompted my initial post. I''m still working on it, though. -Sven --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---