7

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 ?

1
  • Your best bet is to jbuilder: github.com/rails/jbuilder It's included in Rails 4 by default. Commented Sep 16, 2013 at 16:47

3 Answers 3

12

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
Sign up to request clarification or add additional context in comments.

Comments

4

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

Comments

3

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

1 Comment

use the to_json method and pass the options you want, simple easy and flexible. You can easily use different actions to pass more or less attributes from your model. All the detail is in the documentation linked to above

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.