AR inheritance and class methods

In the code below, p.comments.foobar calls #foobar on every comment. Is there a way to call #foobar only on the comments that belong to post "p"?

What you are saying does not make sense to me. p.comments is an array containing the comments that belong to post p. Therefore p.comments.foobar should generate a syntax error as Array does not have a method foobar.

To call foobar on each comment belonging to p do p.comments.each {|c| c.foobar}

Colin

> In the code below, p.comments.foobar calls #foobar on every comment. > Is there a way to call #foobar only on the comments that belong to > post "p"?

> -------------------- > class Comment < ActiveRecord::Base > belongs_to :post

> def self.foobar; end > end

> class Post < ActiveRecord::Base > has_many :comments > end

> p = Post.find_by_id 123 > p.comments.foobar

What you are saying does not make sense to me. p.comments is an array containing the comments that belong to post p. Therefore p.comments.foobar should generate a syntax error as Array does not have a method foobar.

To call foobar on each comment belonging to p do p.comments.each {|c| c.foobar}

Colin

Hi Colin. I agree: an error should occur when calling p.comments.foobar . However, no error occurs.

To use your suggestion:

p.comments.each {|c| c.foobar}

I'll have to change Comment.foobar from a class method to an instance method.

Thanks for your input! Nick

In the code below, p.comments.foobar calls #foobar on every comment. Is there a way to call #foobar only on the comments that belong to post "p"?

-------------------- class Comment < ActiveRecord::Base belongs_to :post

def self.foobar; end end

class Post < ActiveRecord::Base has_many :comments end

p = Post.find_by_id 123 p.comments.foobar

What you are saying does not make sense to me. p.comments is an array containing the comments that belong to post p. Therefore p.comments.foobar should generate a syntax error as Array does not have a method foobar.

Not quite... it looks like an array, but it's not. Otherwise you wouldn't be able to say "p.comments.create(....)" or "p.comments.find(:conditions => ....)" but you can.

The code above works because foobar is defined as class method, not an instance method. Drop that "self." and then your code below is indeed what the grand parent wants.

to be quite precise, if Comment has a class method foo, then calling p.comments.foo calls the foo method, but scoped to those comments with post_id == p.id, so for example if i were to write (contrived example)

class Comment < ...   def self.authors     find(:all).collect {|comment| comment.author}.uniq   end end

then Comment.authors finds you all comment authors, but p.comments.authors finds you every author who has commented on p.

Fred

Thanks Fred that is very helpful. This is one of the constructs in RoR that for a programmer brought up on C is rather difficult to get to grips with as the mechanism by which it works is not obvious, but in practice the result of p.comments.authors is intuitively obvious, so to some extent you just have to grab the ball and run with it.

Colin