1

I have an attribute that is a calculated value based data from various other models.

I am looking for a slick way to cache that value similar to counter_cache but where the value is updated automatically via a custom function. I already have the custom function in the model.

I need to call this function if any of the dependent data is modified. Any suggestions?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Bob Benedict
  • 467
  • 1
  • 4
  • 10

1 Answers1

2

Edit, based on comment:

Ok, so you've got a Like model and a User model. Put the function to update popularity in a method in User, then an after_create or after_save (if it can change after creation) callback on Like to trigger it for the User who received it:

class User < ActiveRecord::Base
  has_many :likes

  def calculate_popularity
    update_attribute(:popularity, existing_function(foo))
  end
end

class Like < ActiveRecord::Base
  belongs_to :user

  after_create :update_user_popularity

  def update_user_popularity
    user.calculate_popularity
  end
end

Obviously, if what receives Likes is various sorts of user activity, rather than the user themselves, you'll need to dig down through your associations to reach the user from the Like, but that shouldn't be too hard.

MrTheWalrus
  • 9,670
  • 2
  • 42
  • 66
  • Good one except the dependency is calculated based on a series of records. I suppose I could cheat this by rolling up the records to a counter_cache or something. Say you were going to calculate a score for someone like how popular they are based on the likes they collected across all their social data on the site. Any time they got a new like, their score should go up. What I need is if there is a change in this collection of data, call this function for this specific object. And from this description, you see before save isn't appropriate either. The dependency is not correct. – Bob Benedict Dec 15 '11 at 20:44
  • That's pretty good. It works perfectly for how I phrased the problem. I am going to make one change though which I thought I would provide in case others read this. I think we may get a race condition as the likes come in from other users. The first like comes in and then a second one comes in before the popularity is updated, and it completes the calc before the first one. I think the smart play is to do something like user.popularity_is_dirty = true and then delay the calc until I need to use or render the score. – Bob Benedict Dec 15 '11 at 23:07