Customize JSON in the Models Themselves

Learn how to customize the JSON in the models.

Optimizing the JSON

Suppose we wanted our widget’s API to use the JSON encoding we showed above. We could certainly achieve this in our controller like so:

def show
  widget = Widget.find(params[:id])

  render json: {
    widget: widget.as_json(
      methods: [ :user_facing_identifier ],
      except: [ :widget_status_id ],
      include:  [ :widget_status ]
    )
  }

end

Of course, if we need to implement the index method, that code would want to use the same options. We could create a private method in Api::V1::WidgetsController called widget_json_options, but what if there is a third place to serialize a widget? For example, if we are using a messaging system, we might encode data in JSON to send it into that system. There’s no reason to use a different encoding, so how do we centralize how widgets are encoded in JSON?

The simplest way is to override as_json in the Widget class itself. Doing that would ensure that anyone who called to_json on a widget would get the single serialization format we’ve designed. This might feel uncomfortable. Why are we giving our models yet another responsibility? What if we really do want a different encoding sometimes? Shouldn’t we separate concerns and have serialization live somewhere else?

Get hands-on with 1200+ tech skills courses.