Reputation: 946
I have a db schema with multiple counter caches. Rather than have the counter caches spread across many tables, I'd like to have a table called user_counters with all of the various counter caches. I'd update these caches from a service object with a method like this:
def update_user_counter(column, user_id)
UserCounter.increment_counter(column, user_id)
end
But, the UserCounter record for the associated user will most likely not have the same ID as the user. What I'd like to do is something like this:
def update_user_counter(column, user_id)
UserCounter.increment_counter(column, UserCounter.where('user_id = "#{user_id}"')
end
Any thoughts as to how I can accomplish this? Thanks!!
Upvotes: 3
Views: 1998
Reputation: 527
If these are 10 attributes associated with a User, is there any reason to not simply make them a part of the User model? If that is the case, the below code will still work (just make the method part of User instead of UserCounter).
If you want to implement it your way, I'd say first make sure that your user_counters
table has an index on user_id (since Rails is dumb about adding indexes and FK's).
Then, you could do this (passing in "column" as a symbol):
class UserCounter < ActiveRecord::Base
#other code
def self.update_user_counter(column, user_id)
counter = UserCounter.find_by_user_id(user_id)
counter.update_attribute(column, counter.read_attribute(column) + 1)
counter.save!
end
end
And in your other model:
class SomeOtherModel < ActiveRecord::Base
#Model code
def update_counter(user)
UserCounter.update_user_counter(:this_column, user.id)
end
end
This solution (or using the update_counter method) both require two database hits, one for the lookup and one for the update. If you need the speed, you could write this directly in SQL:
query = "UPDATE user_counters SET #{column} = #{column} + 1 WHERE user_id = #{user_id};"
ActiveRecord::Base.connection.execute(query);
This assumes that user_id
is unique on user_counters
.
Upvotes: 2