Reputation: 11
I have an array of hashes with comment id and his title:
arr = [{comment_id: 1, title: 'Title 1'}, {comment_id: 5, title: 'Title 2'}]
For each hash I have to add new :key that contain active record model as value:
arr = [{comment_id: 1, user: #<User0x00007fd88dfe1b28>..., title: 'Title 1'},{comment_id: 5, user: #<User0x00005fd58dfe1a31>..., title: 'Title 2'}]
The first solution I found is to make a query for each hash:
arr.each do |h|
h[:user] = Comment.find(h[:comment_id]).user
end
but will be much better to do it with single sql-query something like:
comment_ids = arr.map {|h| h[:comment_id] }
users = User.joins(:comments).order('comments.id').where(comments: {id: comment_ids })
# so here I need to match User with comment_id from comment_ids
Would be nice if someone suggest solution to do this.
Upvotes: 0
Views: 744
Reputation: 26758
First of all, I would find the comments matching the comment IDs, but also includes(:user)
(see Rails eager loading guide) so that we can get the user associated with a comment without needing an additional query:
comments = Comment.where(id: comment_ids).includes(:user)
From this point there are two ways you can go about things. First Enumerable#find (different than ActiveRecord::Base#find, by the way) to pick out the comment corresponding to a particular id, and then read the user from that comment record
arr.each do |h|
comment = comments.find { |comment| comment.id == h[:comment_id] }
h[:user] = comment.user
end
Another way is to use some enumerable manipulation to create a hash where keys are comment IDs, and values are user objects. See index_by and transform_values
users_by_comment_id = comments.index_by(&:id).transform_values(&:user)
arr.each do |h|
h[:user] = users_by_comment_id[h[:comment_id]]
end
Upvotes: 3