Codenoble

Creating quality websites and web applications

Cache Crispies - Fast, Flexible Rails Serializer

Adam Crownoble

There are a lot of options for Rails serialization these days. However, depending on your needs, you may find, in the end, that your viable options are pretty slim.

You could go with the out-of-the-box standard, jbuilder. But it can be pretty slow. You could go with the popular Active Model Serializers, but it's current development status is less than ideal. Plus, it can also be slow and and don't count on caching to rescue you.

You might decide to turn to Netflix's Fast JSON API, which is not a bad idea at all. But you'll have to conform to the JSON:API specification, which might be a major breaking change for your frontend and/or your API consumers. I know the frontend teams I worked with weren't too happy about the prospect of switching to JSON:API when I floated the idea to them. And for good reason! That sort of thing can be a lot of work for relatively little benefit. And if it's a hassle for your own team members, imagine your unhappy API-consuming customers.

It was these sort of issues, along with a push to improve performance by offloading some work from the database and relying more on caching, that led me to write the cache_crispies gem (you know like "cerealization", because cereal and serial areā€¦ don't worry I'm not quitting my day job).

Cache Crispies is intended to feel a bit like Active Model Serializers, with a clean class-based DSL. While also maintaining high levels of performance. And a simple method to enable caching when needed.

Here's an example of a fairly common serializer class just to give you an idea.

class UserSerializer < CacheCrispies::Base
  serialize :id, to: String
  serialize :first_name, :last_name, :display_name
  serialize :company_name, through: :company, from: :name

  serialize :emails, with: EmailSerializer

  show_if ->(_model, options) { options[:current_user]&.support_role? } do
    serialize :phone_number
  end

  def display_name
    "#{model.last_name}, #{model.first_name}"
  end
end

And if you want to enable caching, in most cases it's as simple as adding a do_caching true line. That is enough to tell Cache Crispies to look at the #cache_key for the model or ActiveRecord collection and combine it with it's own cache key and store it in Redis or your cache store of choice. What you wind up with is a cache key that will be busted anytime you change the serializer or any of it's nested serializers. So you don't have to worry about manually invalidating your cache keys when you make a change.

And if you have more complex caching needs (like for the phone_number in the code above that you don't want leaking out to non-support users) you can append your own cache keys like so.

class UserSerializer < CacheCrispies::Base
  do_caching true

  cache_key_addons do |options|
    options[:current_user].support_role?
  end
end

There is a lot more that could be said about this gem, but that's what the documentation is for. I hope that this project can be as helpful and satisfying to you as it has been to me when I've used it.

If you're interested, here are a few resources to help you dig a bit deeper.

ruby gem json caching