Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User.feed enhancement suggestion (Chapter 14) #63

Open
slawagn opened this issue Apr 8, 2022 · 0 comments
Open

User.feed enhancement suggestion (Chapter 14) #63

slawagn opened this issue Apr 8, 2022 · 0 comments

Comments

@slawagn
Copy link

slawagn commented Apr 8, 2022

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 })
  end

I 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)
  end

The 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" DESC

As 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_scope that has been used earlier
  • illustrates the use of SQL operators like OR with ActiveRecord
  • does not explicitly use joins
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant