Active_model_serializers: Changing cache key not working

Created on 16 Jan 2017  路  2Comments  路  Source: rails-api/active_model_serializers

Expected behavior vs actual behavior

Changing a serializer-level cache key with the key option does not change the cache key.

Steps to reproduce

With a basic controller

class ZonesController < ApplicationController
  def index
    render json: Zone.all
  end
end

and basic serializer

class ZoneSerializer < ActiveModel::Serializer
  cache key: 'area', expires_in: 3.hours

  attributes :type, :key

  def type
    'Feature'
  end

  def cache_key
    @cache_key # for debug
  end
end

I would expect the cache key to resemble something like:

area/24-20160217165512052884/attributes/63c314f796ba5ea3898d4a639a9448f4

When instead the key is:

zone/24-20160217165512052884/attributes/63c314f796ba5ea3898d4a639a9448f4

I've verified that the expected key is not present in the cache (memcache in my case). The incorrect key that is being set instead is present in the cache and does contain the cached value, so the cache itself is working.

Environment

ActiveModelSerializers Version (commit ref if not on tag): 0.10.4

Output of ruby -e "puts RUBY_DESCRIPTION": ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16]

OS Type & Version: 10.12.2

Integrated application and version (e.g., Rails, Grape, etc): Rails 5.0.1, api mode

Backtrace

(e.g., provide any applicable backtraces from your application)

Additonal helpful information

Occurs with both memcache/dalli and Rail's memory_store.

development.rb cache section:

# Enable/disable caching. By default caching is disabled.
if Rails.root.join('tmp/caching-dev.txt').exist?
  config.action_controller.perform_caching = true

  config.cache_store = :mem_cache_store, "localhost"
  config.public_file_server.headers = {
    'Cache-Control' => 'public, max-age=172800'
  }
else
  config.action_controller.perform_caching = false

  config.cache_store = :null_store
end
Needs Bug Verification 0.10.x

Most helpful comment

I thought I ran into this problem today too (hadn't seen the issue) but after a brief source dive it looks like this is just a bit of documentation confusion. cache_key comes from the model, so if you want to override it you need to override it there. If for some reason (I happened to have one but it's definitely a rare need) you want to override from the serializer itself, the method to override is object_cache_key. So assuming we have a model, controller, and serializer for Koala it looks like this:

class Koala
  def cache_key
    "#{super}/eucalyptus"
  end
end

class KoalaController
  def show
    render Koala.find(params[:id])
  end
end

class KoalaSerializer
  attributes :id, :food, :claws
  def object_cache_key
    "#{object.cache_key}/from_serializer"
  end
end

All 2 comments

cache key: 'some key'
the key is not working.

I also met this problem, it cause me some problems,when i generate different format json data for the same model in method Index and Show, it will confuse the two formats, as the cache key set by me not working, the cache data of two json format was treated as one, store in redis. I can't get two json formats for one object.

I checked the sourse code of gem, the key set in the model *Serializer was not used first.

This is the sourse code generating the key store in redis or other db.

the key like this: "interviews/20-20170324091427000000/attributes"

  def object_cache_key
    if object.respond_to?(:cache_key)
      object.cache_key
    elsif (serializer_cache_key = (serializer_class._cache_key || serializer_class._cache_options[:key]))
      object_time_safe = object.updated_at
      object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
      "#{serializer_cache_key}/#{object.id}-#{object_time_safe}"
    else
      fail UndefinedCacheKey, "#{object.class} must define #cache_key, or the 'key:' option must be passed into '#{serializer_class}.cache'"
    end
  end

It call the method cache_key(maybe this: http://apidock.com/rails/ActiveRecord/Base/cache_key) first.

I thought I ran into this problem today too (hadn't seen the issue) but after a brief source dive it looks like this is just a bit of documentation confusion. cache_key comes from the model, so if you want to override it you need to override it there. If for some reason (I happened to have one but it's definitely a rare need) you want to override from the serializer itself, the method to override is object_cache_key. So assuming we have a model, controller, and serializer for Koala it looks like this:

class Koala
  def cache_key
    "#{super}/eucalyptus"
  end
end

class KoalaController
  def show
    render Koala.find(params[:id])
  end
end

class KoalaSerializer
  attributes :id, :food, :claws
  def object_cache_key
    "#{object.cache_key}/from_serializer"
  end
end
Was this page helpful?
0 / 5 - 0 ratings

Related issues

AlexCppns picture AlexCppns  路  5Comments

iggant picture iggant  路  4Comments

Andriykoo picture Andriykoo  路  5Comments

steverob picture steverob  路  4Comments

Mifrill picture Mifrill  路  4Comments