# How to make named\_scope aware of association context?

**URL:** <https://www.ruby-forum.com/t/how-to-make-named-scope-aware-of-association-context/154034>\
**Category:** Rails\
**Created:** [November 24, 2008, 6:44pm UTC](https://www.ruby-forum.com/t/how-to-make-named-scope-aware-of-association-context/154034 "2008-11-24T18:44:01Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![sven](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e47c2d/32.png) [@sven](https://www.ruby-forum.com/u/sven)\
**Post date:** [November 24, 2008, 6:44pm UTC](https://www.ruby-forum.com/t/how-to-make-named-scope-aware-of-association-context/154034/1 "2008-11-24T18:44:01Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![sven](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e47c2d/32.png) [@sven](https://www.ruby-forum.com/u/sven)\
**Post date:** [November 24, 2008, 6:50pm UTC](https://www.ruby-forum.com/t/how-to-make-named-scope-aware-of-association-context/154034/2 "2008-11-24T18:50:29Z")

</div>

On Nov 24, 5:43 pm, Sven [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> # Has boolean column 'featured'
> 
> ```
> 
> 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

It should do that by itself. You shouldn’t need to do anything. Have  
you tried it?

Fred

---

<div class="post-metadata">

**Author:** ![sven](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e47c2d/32.png) [@sven](https://www.ruby-forum.com/u/sven)\
**Post date:** [November 24, 2008, 7:08pm UTC](https://www.ruby-forum.com/t/how-to-make-named-scope-aware-of-association-context/154034/3 "2008-11-24T19:08:08Z")

</div>

On Mon, Nov 24, 2008 at 12:49 PM, Frederick C. \<  
removed\_email\_address@domain.invalid\> 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]

---

<div class="post-metadata">

**Author:** ![sven](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e47c2d/32.png) [@sven](https://www.ruby-forum.com/u/sven)\
**Post date:** [November 24, 2008, 7:26pm UTC](https://www.ruby-forum.com/t/how-to-make-named-scope-aware-of-association-context/154034/4 "2008-11-24T19:26:19Z")

</div>

On 24 Nov 2008, at 18:07, Sven Aas wrote:

> ```
> :conditions =>  
> 
> ```
> 
> 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

---

<div class="post-metadata">

**Author:** ![sven](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e47c2d/32.png) [@sven](https://www.ruby-forum.com/u/sven)\
**Post date:** [November 25, 2008, 6:33pm UTC](https://www.ruby-forum.com/t/how-to-make-named-scope-aware-of-association-context/154034/5 "2008-11-25T18:33:24Z")

</div>

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
