How do I calculate a computed value in a model when showing or indexing over that model in its controller?
I'm new to Rails but not new to programming or webdev.
I have a Student
model that uses a service object to pull data from Google Cloud Firestore for its level
attribute, an integer. I have hooked the service object's method into an update_level
method on the Student
model using the before_save
ActiveRecord callback. This method checks the last time the student's level was updated from a column in the database and if it's been more than 10 minutes it will fire the method to check Cloud Firestore. This works fine when creating or updating these objects, but one of the reasons for this Rails app is to present up-to-date information to teachers about their students. (I promise this isn't creepy learning analytics, it's for a bespoke game for a special curriculum.)
What is the best, most Rails-like way to hook this functionality into the index
and show
controller methods, such that if I'm showing a Student
record or indexing over a list of Students, fire the same update_level
method (or one like it) for each student. Now, my mind immediately starts thinking about some kind of job queue or ActionCable solution to this, but that seems far too complicated. I'm trying to minimize unnecessary calls to Firestore, but I want to make sure the data I'm presenting is relatively up to date.
What is the Rails way of doing this?
If it helps, here's the gist of the code fire off to update a Student's level. FirestoreGetter
is my service object that wraps Google's Cloud Firestore gem with some formatting niceties.
def firestore_getter
@firestore_getter ||= FirestoreGetter.new
end
def update_level
if self.last_level_checked.nil? || self.last_level_checked < 10.minutes.ago # FIXME: abstract this to some setting
retrieved_level = firestore_getter.retrieve_student_level username
self.level = retrieved_level
self.last_level_checked = DateTime.now
end
end
After sleeping on it, I believe the best way (and the way that requires the fewest queries to Cloud Firestore) is to just download the whole Firestore DB and update from that object every 10 or so minutes with a scheduler of some kind.
I believe the answer to my original question is something like: do it in the controller's index and show methods, but it will be bad and inefficient and slow and violate RESTful practices and smells bad.