In my app, I have a large complex model with many associations. I need to serve it as json. The model's size and complexity, however, mean that assembling the json version is costly both in terms of CPU and RAM. Fortunately, since the model is not frequently updated it's a good candidate for caching. I'd like to keep a cached version of the model's json string on a static file hosting service (e.g. S3), handled by activestorage.
The code below summarizes what's I've done so far. In the controller, incoming GET requests for the model are redirected to the cached version on activestorage. The model keeps the cached version up-to-date using an after_save
callback.
class ComplicatedModelController < ApplicationController
def show
@complicated_model = ComplicatedModel.find(params[:id])
redirect_to @complicated_model.activestorage_cached_json_response.url
end
class ComplicatedModel < ActiveRecord::Base
has_one_attached :activestorage_cached_json_response
after_save do
# updated cached version - how can I do this WITHOUT retriggering the aftersave callback?
self.activestorage_cached_json_response.attach(
io: StringIO.new(self.as_json), # this step is costly
filename: "ComplicatedModel_#{self.id}.json",
content_type: 'application/json'
)
end
end
The problem is that updating the activestorage attachment within the aftersave callback creates an infinite loop: this step saves the model again, and so retriggers the callback. To make this strategy work, I'd need to update the activestorage attachment WITHOUT triggering the aftersave callback. Is this possible?