-
Notifications
You must be signed in to change notification settings - Fork 368
Open
Description
The User model has a feed method that is currently implemented the following way:
# Listing 14.47: The final implementation of the feed
def feed
following_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
Micropost.where("user_id IN (#{following_ids})
OR user_id = :user_id", user_id: id)
end
# Listing 14.50: Using a join to make the feed.
def feed
part_of_feed = "relationships.follower_id = :id or microposts.user_id = :id"
Micropost.joins(user: :followers).where(part_of_feed, { id: id })
endI think a slightly more elegant solution may be proposed here, for instance:
# User.rb
def feed
Micropost.appearing_in_feed_of(self)
end
# Micropost.rb
scope :appearing_in_feed_of, ->(user) do
where( user_id: user.following.select(:id))
.or(where user_id: user.id)
endThe following SQL query is produced by the code above:
SELECT "microposts".* FROM "microposts"
WHERE (
"microposts"."user_id" IN (
SELECT "users"."id"
FROM "users"
INNER JOIN "relationships"
ON "users"."id" = "relationships"."followed_id"
WHERE "relationships"."follower_id" = ?
)
OR "microposts"."user_id" = ?
)
ORDER BY "microposts"."created_at" DESCAs you can see, just like the solution currently used, the one proposed here also produces a single SQL query with subquery, but:
- does so in a more idiomatic way, that is, without using strings of plain SQL
- illustrates how scopes can be used, aside from the
default_scopethat has been used earlier - illustrates the use of SQL operators like
ORwith ActiveRecord - does not explicitly use joins
Metadata
Metadata
Assignees
Labels
No labels