Skip to main content

API low-level caching

Ruby • Asked by Sean M

Hey Chris,

I am a bit confused regarding API caching. I am using JSONAPI spec and fast_jsonapi gem and trying to cache the vehicle itself on show action and if there are params coming over like include=service_notes,service_alerts then I would like to cache those too. This is my initial approach but not sure if it is right.

I have 2 main issues:

  1. For the vehicle caching itself is there a better approach than my vehicle = Vehicle.find_cached(params[:id]). This is not using updated_at but an after save callback to update the cache if vehicle has been updated. I just don't see if I could somehow use sth like Rails.cache.fetch(["vehicles", vehicle], version: vehicle.updated_at) as it is proposed here: https://github.com/rails/rails/pull/29092 since this needs the vehicle instance. As you see the set_vehicle controller method is pretty awkward.

  2. Does this Rails.cache.fetch(['vehicles', vehicle, include_params], version: vehicle.updated_at) make any sense? I am trying to cache the query based on the different include params. Maybe it is overkill and I could just include everything and cache it that way like:

    Rails.cache.fetch(['vehicles', vehicle, 'with_includes'], version: vehicle.updated_at) do
        Vehicle.includes(:vehicle_alerts, :service_notes, :service_intervals).find(params[:id])
    end
    

What do you think?

I hope you can help me out! Thanks in advance!

Code is below:

class ServiceNote < ApplicationRecord
    belongs_to :vehicle, touch: true
end

same with (ServiceAlert and ServiceInterval)

class Vehicle < ApplicationRecord
    after_save :update_cache
    has_many :vehicle_alerts, dependent: :delete_all
    has_many :service_notes, dependent: :delete_all
    has_many :service_intervals, dependent: :delete_all

    def update_cache
        Rails.cache.write(['vehicles', vehicle_id], self)
    end

    def self.find_cached(vehicle_id)
        Rails.cache.fetch(['vehicles', vehicle_id]) { find(vehicle_id) }
    end
end

vehicles_controller

before_action :set_vehicle, only: [:show]

def show
    render json: VehicleSerializer.new(@vehicle, options).serialized_json
end

private

def set_vehicle
    vehicle = Vehicle.find_cached(params[:id])

    @vehicle = Rails.cache.fetch(['vehicles', vehicle, include_params], version: vehicle.updated_at) do
        Vehicle.includes(include_params).find(params[:id])
    end

    authorize @vehicle
end

vehicle_serializer (with fast_jsonapi gem), (same for vehicle_alerts and service_notes)

has_many :service_intervals do |vehicle, params|
    if params[:include] && params[:include].include?(:service_intervals)
        vehicle.service_intervals
    end
end

I have the same question.


Hi,
You could cache like this:

def method_name
return Rails.cache.fetch('method_name', :expires_in => 1.hours) {
# do something
}
end

Why not?
What is stopping you? :)


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 27,623+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.