All threads / How do I cache a complex JSON response (with a lot of belongs_to associations) to be used by Vue.js in the frontend?

Ask A Question

Notifications

You’re not receiving notifications from this thread.

How do I cache a complex JSON response (with a lot of belongs_to associations) to be used by Vue.js in the frontend?

TL asked in Rails

Thanks to Chris nice tutorials, we just rewrote a slow interface in our app to use Vue.js. Now Rails is just generating the JSON to be consumed by Vue.js in the view.

What I'm trying to achieve is to generate a cached JSON response using read_multi or fetch_multi, so all Conversations (there are 20 on each pagination) are loaded on a single call to memcached.

Le'ts say I have a model called Conversation, that belongs to an user, to a tourist, to a property, and it also has many replies.

class Conversation
  belongs_to :user
  belongs_to :tourist
  belongs_to :property
  has_many :replies
    has_many :holidays

    def generate_json
        {

        tourist: {
          name: tourist.name,
          email: tourist.email,
        property: {
          id: property.id,
          image_url: property.pictures.first.try(:image).try(:url,:thumb),
          property_code: property.property_code,
          title: property.title_br,
        },
        recent_replies: replies.last(5).map(&:generate_json) 
      }
    end


end

For the has_many associations, I simply use touch: true in the other side of the association, so model Reply is a belongs_to :conversation, touch: true, which takes care of updating Conversation's updated_at if it changes and the cache is automatically updated.

But every time I try to cache a model like this (wether in a view fragment or, in this case, in a JSON response) I end up with a huge and complex cache key due, mainly, to the belongs_to association on the cached model. Something like this for example:

Rails.cache.fetch(self.cache_key, self.user.cache_key, self.tourist.cache_key, self.property.cache_key) do
   ... generates the JSON for this model
end

Justin Weiss has a nice tutorial (altough a bit complex) of how to cache complicated JSON responses (https://www.justinweiss.com/articles/a-faster-way-to-cache-complicated-data-models/) but as far as I could understand he's using manually expiring cache keys.

I'm a little bit lost at this point. How would you guys implement caching for this type of JSON structure?

One idea is to use just the self.cache_key in the cache key for the Conversation, (1) rely on touch: true for the has_many associations and (2) write manual after_commit :touch_conversations for the belongs_to associations, something like this:

model Tourist

    has_many :conversations
    after_commit :touch_conversations

    def touch_conversations
        self.conversations.update_all(updated_at: Time.now)
    end

end

The problem with this approach is that some users already got + 200k conversations for example. Updating them all takes at least 4 seconds in my tests, and I'm afraid interfaces will start to get sluggish over time.

Join the discussion

Want to stay up-to-date with Ruby on Rails?

Join 37,629+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    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.