Home > Back-end >  How to pluck id of has_one associations?
How to pluck id of has_one associations?

Time:04-23

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.

  • Related