Rails如何从Post集合中高效获取唯一关联User(作者)?
Great question! Let's walk through your current approaches first, then dive into a more efficient solution.
Breaking down your existing methods:
@posts.map(&:author).uniq(&:id): This is the least performant option by far. It triggers an N+1 query (one to load posts, then one per post to load its author), and handles deduplication in Ruby. For large post collections, this wastes both database resources and Ruby processing power—something the database is way better at handling.User.where(id: @posts.pluck(:author_id)): This is a solid improvement!pluck(:author_id)grabs just the author IDs in one query, thenUser.where(...)fetches matching users in another. The database automatically deduplicates users even ifpluckreturns repeated IDs, so you get unique authors. That said, we can trim this to a single database query for even better speed.
The Most Efficient Solution
Instead of two separate database calls, we can combine the post filter and user lookup into one optimized query using ActiveRecord joins:
# Make sure your models have the right associations: # Post model: belongs_to :author, class_name: 'User' # User model: has_many :posts, foreign_key: :author_id User.joins(:posts).merge(@posts).distinct
If you prefer being explicit with post IDs, this works too:
User.joins(:posts).where(posts: { id: @posts.ids }).distinct
Why this is better:
- Single database query: Eliminates the extra round trip from the
pluckstep, cutting down on database overhead. - Database-level deduplication: The
DISTINCTclause tells the database to return only unique users, so we don't waste Ruby cycles processing duplicates. - Optimized relational logic: Databases are built for this kind of cross-table filtering and deduplication—they'll handle it faster than Ruby ever could.
Quick Tip
If @posts is an ActiveRecord Relation (not an already-loaded array of posts), merge(@posts) will seamlessly combine your post query conditions into the user query, keeping everything as one streamlined SQL statement.
内容的提问来源于stack exchange,提问作者Steven Jeffries

