Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 4 - Customizing (json) format of response objects in Rails

I have a Rails Controller who responds with JSON objects. Let's take this theoretical example :

respond_to :json
def index 
  respond_with Comment.all
end

This would respond with something like

[{"id":1,"comment_text":"Random text ", "user_id":1  ,"created_at":"2013-07-26T15:08:01.271Z","updated_at":"2013-07-26T15:08:01.271Z"}]

What i'm looking for is a "best practice" method to interfere with the formating of the json object and return something like this :

[{"id":1,"comment_text":"Random text ", "username": "John Doe", "user_id":1  ,"created_at":"3 hours ago"}]

As you can see, i'm adding a column that doesn't exist in the database model "username" , i'm taking out "updated_at" , and i'm formatting "created_at" to contain human readable text rather than a date.

Any thoughts anyone ?

like image 448
Cosmin Avatar asked Jul 26 '13 16:07

Cosmin


3 Answers

Overwriting as_json or working with JSON ERB views can be cumbersome, that's why I prefer using ActiveModel Serializers (or RABL):

class CommentSerializer < ActiveModel::Serializer
  include ActionView::Helpers::DateHelper

  attributes :id, :created_at

  def created_at
    time_ago_in_words(object.created_at)
  end

end

Look here for more information:

  1. https://github.com/rails-api/active_model_serializers
  2. https://github.com/nesquena/rabl
like image 149
lawitschka Avatar answered Nov 12 '22 00:11

lawitschka


2 ways:

first: define a view, where you build and return an hash that you'll convert to json.

controller:

YourController < ApplicationController
  respond_to :json

  def index
    @comments = Comment.all
  end
end

view: index.json.erb

res = {
  :comments => @comments.map do |x|
    item_attrs = x.attributes
    item_attrs["username"] = calculate_username
  end
}

res.to_json.html_safe

second: use gem active_model_serializers

like image 38
Alive Developer Avatar answered Nov 12 '22 00:11

Alive Developer


I'd redefine the as_json method of your model.

In your Comment model,

def username
  "John Doe"
end

def time_ago
  "3 hours ago"
end

def as_json(options={})
  super(:methods => [:username, :time_ago], except: [:created_at, :updated_at])
end

You don't have to change your controller

Take a look at the documentation for as_json

like image 3
RedXVII Avatar answered Nov 11 '22 23:11

RedXVII