class Post
has_one :latest_comment, -> { order(created_at: :desc) }, class_name: 'Comment'
end
I want to do something like:
Post.joins(:latest_comment).pluck('latest_comment.id')
but it's not valid syntax and it doesn't work.
Post.joins(:latest_comment).pluck('comments.id')
Above works but it returns ids of all comments for a post, not only of the latest.
CodePudding user response:
Try with :'latest_comments.id'
Post.joins(:latest_comment).pluck(:'latest_comments.id')
Take care to the singular/plural nouns.
Solution found thanks to this StackOverflow question but your case is even trickier because the joins
requires the singular name latest_comment
but pluck requires the plural latest_comments
.
CodePudding user response:
I couldn't find a good, existing answer. This is the closest.
The problem isn't really pluck
. The problem is that joining on a has_one
is the same as joining on the table itself. In this case, it's equivalent to Post.joins(:comments)
.
Without getting into custom SQL or Arel
, a simple solution is to just eager-load the records:
Post.includes(:latest_comment) # eager-loads latest_comments in subquery
.find_each # optional: batches data to save memory
.filter_map(&:latest_comment) # map to `latest_comment` and remove nils
.map(&:id) # finally, get the ids
This isn't nearly as performant as a pluck
since it's retrieving every column on both tables and instantiating all of the model instances.
You can improve performance a bit by adding select(:id)
after Post
so that it only retrieves the id
for posts.