When rendering your ActiveRecord models in your controller as JSON you often wanna include more than just the default attributes that calling #to_json on the model gives you. There are various hacks described on Stackoverflow, like overriding the #to_json, #as_json and #serializable_hash methods, two of which I can even find in my current (legacy) project.

Today I wanna show you the OOP way how to do this. Spoiler: We'll create a class.

Let’s say we’re dealing with a Book class, which has some attributes: title, author and a released_at column. We also have a method released? which returns true if the book has already been released, otherwise it returns false:

class Book < ApplicationRecord
  # Our attributes:
  # - title <String>
  # - author <String>
  # - released_at <Date>

  def released?
    Time.zone.now > released_at
  end
end

The next step is to include a gem which deals with the JSON serialization itself: active_model_serializers. Add it to your Gemfile.

Next we invoke a new generator that active_model_serialization gives us: rails g serializer book. That will create a new file (and directory), app/serializers/book_serializer.rb with the following content:

class BookSerializer < ActiveModel::Serializer
  attributes :id
end

You can probably already see what our next step will look like. We will modify our BookSerializer to include the attributes and methods we want to put into our JSON representation. In our case, we'll add our attributes from our Book class and also include our released? method, like so:

attributes :id, :title, :author, :released_at, :released?

Then, whenever you need a JSON representation of a Book record (like in your controller actions), call BookSerializer.new(book).to_json. The response will then looks like this (pretty printed, so it's easier to read):

{  
  "id":1,
  "title":"Generation X",
  "author":"Douglas Coupland",
  "released_at":"1991-03-15",
  "released?":true
}