Search code examples
ruby-on-railsactiverecordrails-activerecord

Get all nested records for multiple activerecords


Lets say there are two models: User and Post where each post belongs to a user and a user can have many posts.

If you do @user.posts you get all posts for @user. But, given @users, is there a more elegant way than Post.where(user_id: @users.map(&:id)) to get all posts for @users? Something like @users.posts?


Solution

  • Based on your comment that @users is an ActiveRecord::Relation, the simplest method is to let Active Record figure it out for you:

    Post.where(user: @users)
    # SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN
    #   (SELECT "user"."id" FROM "users")
    

    This performs a single database query and lets the database do all the heavy lifting with a sub-select (your sub-select might look different... in my example @users was simply User.all).

    For cases when you aren't using .map to get an id field, you might want to consider .pluck to return an array of values from the database without fetching entire records. For example:

    @users.pluck(:name)
    
    # instead of
    
    @users.map(&:name)
    

    In theory you can use .pluck in your scenario but if you have a lot of users you'll generate and send a very long SQL query containing an array of user IDs instead of letting the database do the work itself...

    Post.where(user_id: @users.pluck(:id))
    # SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN
    #   (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 64, 65, 66, 67, 68, 69, 70, 72, 73, 71, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 97)