Ask A Question

Notifications

You’re not receiving notifications from this thread.

API low-level caching

Sean M asked in Ruby

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
Reply

I have the same question.

Reply

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? :)

Reply
Join the discussion
Create an account Log in

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

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

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

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

    © 2023 GoRails, LLC. All rights reserved.