Revising named_scope semantics in associated classes

Suppose I have the following models:

  class Post < ActiveRecord::Base     has_and_belongs_to_many :categories     named_scope :active, :conditions => {:active => true}   end

  class Category < ActiveRecord::Base     has_and_belongs_to_many :posts   end

I can call Post.active to get the set of all active Post objects. And I can call some_category.posts.active to get all active Post objects associated with some_category.

But what if I want slightly different semantics for the active posts within a category? Perhaps there is an additional condition that should apply in this case, as suggested by the new method shown here:

  class Category < ActiveRecord::Base     has_and_belongs_to_many :posts

    def self.active_posts       channels.active.all :conditions => {:show_in_category => true}     end   end

Instead of introducing a new active_posts method, is there any way to define conditions that should be merged into the named_scope when it is reference from the associated class?

-Sven

I’m a little confused by your example. Do you mean posts instead of channels? :show_in_category is on Post, correct?

Assuming posts and :show_in_category on Post, couldn’t you just add a second named_scope to Post, show_in_category (for lack of a better name)?

class Post < ActiveRecord::Base named_scope :active, :conditions => { :active => true } named_scope :show_in_category, :conditions => { :show_in_category => true } … end

Then you could do some_category.posts.active or some_category.posts.active.show_in_category as you see fit.

Thoughts?

Regards, Craig

Sorry, I made some mistakes when I tried to simplify my project code. I'm trying to amend the semantics of an existing named_scope when it's called from an association, not add an additional one. Here's a more complete example (which I hope I've gotten right):

  class Post < ActiveRecord::Base     has_many :category_assignments     has_many :categories, :through => :category_assignments     named_scope :active, :conditions => {:active => true}   end

  class Category < ActiveRecord::Base     has_many :category_assignments     has_many :posts, :through => :category_assignments   end

  class CategoryAssignment < ActiveRecord::Base     belongs_to :post     belongs_to :category     # has attribute show_in_category which allows     # showing/hiding posts on a per-category basis   end

I want to be able to do this

  some_category.posts.active

And get the semantics of the active_posts method below:

  class Category < ActiveRecord::Base     has_many :category_assignments     has_many :posts, :through => :category_assignment

    def active_posts       posts.active.all :conditions => ['category_assignment.show_in_category = ?', true]     end   end

So when I call

  Post.active

I get the set of all active posts. But when I call

  some_category.posts.active

I get the set of all active posts in some_category where show_in_category is true (like calling my active_posts method, but using a named_scope instead).

One possibility is to do something like this:

  class Category < ActiveRecord::Base     has_many :category_assignments     has_many :posts, :through => :category_assignment     has_many :visible_posts, :class_name => 'Post', :through => :category_assignment,              :conditions => ['category_assignment.show_in_category = ?', true]   end

And then remember to call

  some_category.visible_posts.active

This lets me use the named scope instead of a method but the semantics aren't right. I'm trying to express the notion that active category.posts are subject to an additional restriction relative to active posts. I'm not trying to divide _posts_ into two groups. I'm just trying to restrict _active_ posts within a category.

-Sven

Restricting is dividing your set into those items you want and those you don’t. Since you have attributes across two models, Post#active and CategoryAssignment#show_in_category, though, I don’t think you can combine them into one named_scope. I think you’ll have to do something like you suggested at the end of your last message, or you’ll have to wrap everything in a class method to have the semantics that you want.

Regards, Craig