Ruby

Deviseで使用するmodelのインスタンスをキャッシュする

More than 5 years have passed since last update.

ログを見てるとDeviseのユーザーがログイン状態にあるかどうかのチェックで毎回SQLをはいているので、この部分をキャッシュできないかな?とDeviseとWardenのコードを追ってみました。

https://github.com/plataformatec/devise
https://github.com/hassox/warden

(ここではUserモデルがDeviseを使用してるとします。)
かなり省略しますが、最終的にはwarden_compat.rb内の deserializeが呼ばれ

      klass = ActiveSupport::Inflector.constantize(klass_name)
      if klass.respond_to? :serialize_from_session
        klass.serialize_from_session(*args)
      else
        Rails.logger.warn "[Devise] Stored serialized class #{klass_name} seems not to be Devise enabled anymore. Did you do that on purpose?"
        nil
      end

そこでserialize_from_sessionを呼んでいます。
devise内のauthenticatable.rbを見ると

authenticatable.rb
    def serialize_from_session(key, salt)
        record = to_adapter.get(key)
        record if record && record.authenticatable_salt == salt
    end

どうやらここでUserデータを読み込んでいて、このモジュール自体はUserモデルでインクルードしているので、この部分をUserモデル上でオーバーライドすればできそうです。

  def self.serialize_from_session(key, salt)
    Rails.cache.fetch("#{User.name}_#{key[0]}") { 
      record = to_adapter.get(key)
      record if record && record.authenticatable_salt == salt
    }
  end

もちろん適切なキャッシュのクリアは必要ですが、こんな感じでUserのデータをキャッシュできます。