Skip to content

User.feed enhancement suggestion (Chapter 14) #63

Description

@slawagn

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions