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