Sorting By Last Comment? ("post.comments.first.created_on")

I’m trying to order a table based on the last comment, and have tried
almost everything and still can’t get it working.

My specs are just like the API’s
(ActiveRecord::Associations::ClassMethods)

class Post < ActiveRecord::Base
belongs_to :author
has_many :comments
end

Consider the following loop using the class above:

for post in Post.find(:all)
puts "Post: " + post.title
puts "Written by: " + post.author.name
puts "Last comment on: " + post.comments.first.created_on
end

I tried doing:

“:order => ‘@posts.comments.first.created_on DESC’” – but can’t get it
working.

How could I order the table based on “post.comments.first.created_on”?

Aah,
it appears you misunderstand how the :order key works in a find,
it’s all a question of SQL.

Firstly,
you want to make your code efficient,
so you want to achieve your outcome in as few DB queries as possible.

For every has_many, or belongs_to, it needs to make a database query,
so instead, we’ll “eager” load these when we do our find.

all_with_attributes = Post.find(:all, :include => [:author, :comments]

but, actually, we don’t need this,
if you’re not using the comments, and only the time of the comment,
instead we’ll define a “last_comment” in your class

class Post < ActiveRecord::Base
belongs_to :author
has_many :comments
has_one :last_comment,
:class_name => “Comment”,
:order => “comments.created_at DESC”
end

This now let’s your write @post.last_comment.created_at

so, now our find should be;

Post.find(:all,
:include => [:author, :last_comment],
:order => “comments.created_at DESC”
)

And I think we’ll have what you need.

If that’s too confusing for you,
you can just do the following in ruby (rather than in the db)

Post.find(:all,
:include => [:author, :comments]
).sort_by{|p| p.comments.last.created_at}

  • the include is optional, but seriously, you need to be doing this
  • watch your development.log when you don’t

or

Post.find(:all,
:include => [:author, :comments],
:order => “comments.created_at DESC”
)

would probably work too.

Bob S. wrote:

I’m trying to order a table based on the last comment, and have tried
almost everything and still can’t get it working.

class Post < ActiveRecord::Base
belongs_to :author
has_many :comments
end

Consider the following loop using the class above:

for post in Post.find(:all)
puts "Post: " + post.title
puts "Written by: " + post.author.name
puts "Last comment on: " + post.comments.first.created_on
end

Matthew! You’re awesome! Thank you so much for your informative post. I
can’t tell you how appreciative I am. Thank you, thank you, thank you :slight_smile:

I tried the first method, and it works great. I had issue with
displaying the latest date, so I used your second approach,
specifically:

Post.find(:all,
:include => [:author, :comments],
:order => “comments.created_at DESC”
)

Then in the view, I incorporated this: post.comments.first.created_at,
and it works perfectly like how I wanted.

Thank you so much for your help, Matthew!!

Matthew R. wrote:

Aah,
it appears you misunderstand how the :order key works in a find,
it’s all a question of SQL.

Firstly,
you want to make your code efficient,
so you want to achieve your outcome in as few DB queries as possible.

For every has_many, or belongs_to, it needs to make a database query,
so instead, we’ll “eager” load these when we do our find.

all_with_attributes = Post.find(:all, :include => [:author, :comments]

but, actually, we don’t need this,
if you’re not using the comments, and only the time of the comment,
instead we’ll define a “last_comment” in your class

class Post < ActiveRecord::Base
belongs_to :author
has_many :comments
has_one :last_comment,
:class_name => “Comment”,
:order => “comments.created_at DESC”
end

This now let’s your write @post.last_comment.created_at

so, now our find should be;

Post.find(:all,
:include => [:author, :last_comment],
:order => “comments.created_at DESC”
)

And I think we’ll have what you need.

If that’s too confusing for you,
you can just do the following in ruby (rather than in the db)

Post.find(:all,
:include => [:author, :comments]
).sort_by{|p| p.comments.last.created_at}

  • the include is optional, but seriously, you need to be doing this
  • watch your development.log when you don’t

or

Post.find(:all,
:include => [:author, :comments],
:order => “comments.created_at DESC”
)

would probably work too.

Bob S. wrote:

I’m trying to order a table based on the last comment, and have tried
almost everything and still can’t get it working.

class Post < ActiveRecord::Base
belongs_to :author
has_many :comments
end

Consider the following loop using the class above:

for post in Post.find(:all)
puts "Post: " + post.title
puts "Written by: " + post.author.name
puts "Last comment on: " + post.comments.first.created_on
end

Why are you doing comments.first? You’ll only ever get the most recent
comment if there’s only one there.

post.comments.find(:first, :order => “created_on DESC”).created_on

should get you what you need.

Also, just so you know, the Ruby Way of your code is as follows:

Post.find(:all).each do |post|

end

Jason