Andy Harvey
Andy Harvey

Reputation: 12653

How to create a (high performance) activity feed from several models?

In a Rails app I want to combine several models into a single activity feed.

For example, I have Post, Comment, Photo, Status models. Each one belongs to a User, an Institution, and a City. On a User/Institution/City show page I want to display a chronological list of the latest activity.

From reading around and from other questions on SO, there appear to be two schools of thought on this.

  1. Create a polymorphic ActivityFeed model where e.g. a User has_many :posts as: feedable. Then render the ActivityFeed collection on the respective show pages.
  2. Create and render a combined array e.g. @user_feed = @user_photos + @user_comment +..

But I haven't seen much discussing the pros and cons of each approach.

Has any one else attempted something similar? What issues should I be thinking about or planning for in choosing an approach? How well do each perform (especially as the database gets larger)?

My requirements are:

  1. To display all items that belong to the parent model.
  2. To have several different types of parent model (User, Institution, City, etc).
  3. To render a different view partial for each item in the activity feed, depending on its class.

Grateful for any thoughts, personal experiences, or pointers to further information on this. Should I be looking for a third option? I'm particularly interested in the performance of creating a combined array from several queries.

Thanks

Upvotes: 3

Views: 1707

Answers (1)

Viktor Trón
Viktor Trón

Reputation: 8884

Let me add a few more issues to your requirements

  1. ease of display all items belonging to parent model
  2. ease of allowing for different types of parent model
  3. ease of class-dependent template rendering
  4. ease of refactoring shared activity functionality
  5. ease of integrating potential activity control functionality (mark as read, subscribe, follow, share etc)
  6. ease of calculating polymorphic feed, say in reverse chronological order of activities of various types.
  7. ease of calculating aggregated activity count on a parent

For me 5 and 6 and 7 defo tips it in favour of the first option, my code would be:

class Activity
  belongs_to :activity, polymorphic: true
  belongs_to :user, counter_cache: true
  belongs_to :institution, counter_cache: true
  belongs_to :city, counter_cache: true
end

your scope for city newsfeed (demonstrating 1,2,6)

city.activities.order('updated_at DESC').limit(20)

note that this is a cheap search on one table only that can already give you enough for a quick list since association loading (would be .includes(:activities)) is not necessary to display something like.

Joe from NYU, New York has posted a comment
Mel from UCL, London has added a new photo

4 is trivial if activity is a separate class and 5 also smooth with standard activity controller. for shared rendering partials like the quicklist views/activities will be a natural place. 7 is easily done with the counter_cache. as a bonus, by allowing has_many :activities on each type, you could distinguish types of activities, like create, update, read, etc.

hope this helps

Upvotes: 3

Related Questions