Jordan T-H

Joined

2,320 Experience
8 Lessons Completed
2 Questions Solved

Activity

Posted in Which native app technology to pair with Rails

Basecamp uses a native frame around a WkWebview. They use this turbolinks wrapper and have given a nice presentation about it.

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.

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

Not sure what the etiquette is for answering or following up one's own question, but I ended up modeling this, because I realized I need some pretty complicated and persistent logic for each document's lifecycle, a subject of another question.

I'm pretty new to Rails, and I was wondering what the "right" way of architecting a small app would be given the following scenario. Users create Rooms, then from there add to them a number of references ("Documents") to track that are pulled in from Google Cloud Firestore. Rooms are basically table displays for these collections of Documents. Documents can be in more than one Room. I have a service object to do stuff with Cloud Firestore.

I see two ways of doing this:

The first is to simply store each Document's id in a serialized text attribute (or a store) on a given Room. This seems inelegant and non-Rails-y, especially when I think about the kind of query I'd need to construct to analyze documents across all rooms. Or maybe not? What makes this interesting is that it is simple. I can just query Firestore for the relevant information each time I want to display it. Right now, there's really only one attribute in Firestore I'm interested in, so I could even directly store the filtered hash from the Firestore collection in this attribute as an ActiveRecord::Store, do a comparison every time a Room is accessed (I think the Firestore gem might even do this caching), then update it from Firestore.

The second is to add a Document model for each document. Instead of working with Document ids in arrays from a given Room, I'd have a table for Documents, and a join table for the connections between Documents and Rooms. In this situation, I'd like some kind of caching or something, where any time I get information about a Document back from a query I update it in the database, or some way of maintaining this isomorphism while preserving how easy it is to work with ActiveRecord. This app is read-only for now, and it's not catastrophic if something is a few minutes out of date.

Has anyone tackled a situation like this, working from two databases and trying to reconcile them? I'm tempted to just start with the first version because it's so simple, then grow out to the second, unless someone has some enlightened ideas. Thank you in advance for reading.

logo Created with Sketch.

Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

© 2020 GoRails, LLC. All rights reserved.