I have a user profile page that has a sidebar with user stats like not unlike the Stack Overflow profile page (e.g., total visits, number of badges).
The trouble is that currently I'm hitting the database and calculating these stats with every single request. I can implement fragment caching to cut down on this, but is there a better way to handle this type of thing?
Storing the aggregated summary data in the database seems like it might lead to problems (i.e., inconsistency).
You could store this information in the database instead of recalculating it, using:
As an example, if measuring the number of badges, you could create a database field in User
called badges_count
, then in the Badge model, have belongs_to :user, :counter_cache => true
. Now, whenever the number of badges changes, you can access the count without any new calculations at @user.badges_count
.
A basic implementation: http://asciicasts.com/episodes/23-counter-cache-column
Let's say you have a field that measures behavior that is more complex than a simple count. In this case, just implement callbacks that update a field whenever a certain action occurs using before_save
, after_save
, before_create
, etc.
Storing the data in your database will only be inconsistent if you're doing it wrong. There are a finite number of paths through which any statistic can be updated, and you should ensure that all paths are covered in updating whichever field you are using. Rails does it for you with counter_caching, and you have to do it yourself if you use custom callbacks or you have some unusual situation.