132

Suppose you're in your users controller and you want to get a json response for a show request, it'd be nice if you could create a file in your views/users/ dir, named show.json and after your users#show action is completed, it renders the file.

Currently you need to do something along the lines of:

def show
  @user = User.find( params[:id] )
  respond_to do |format|
    format.html
    format.json{
      render :json => @user.to_json
    }
  end
end

But it would be nice if you could just create a show.json file which automatically gets rendered like so:

def show
  @user = User.find( params[:id] )
  respond_to do |format|
    format.html
    format.json
  end
end

This would save me tons of grief, and would wash away that horribly dirty feeling I get when I render my json in the controller

Matthew
  • 5,435
  • 6
  • 25
  • 29
  • Looking at this post now, it looks like this wouldn't save me much, but i have more complicated cases, trust me when I say this is causing me headaches – Matthew Jan 18 '10 at 18:33
  • 1
    In Rails 3, you can just call `format.json` with a `show.json.erb` file. See my answer. – James Lim Dec 30 '12 at 17:13

9 Answers9

67

You should be able to do something like this in your respond_to block:

respond_to do |format|
    format.json 
    render :partial => "users/show.json"
end

which will render the template in app/views/users/_show.json.erb.

Guy Grin
  • 1,968
  • 2
  • 17
  • 38
Alex Reisner
  • 29,124
  • 6
  • 56
  • 53
58

Try adding a view users/show.json.erb This should be rendered when you make a request for the JSON format, and you get the added benefit of it being rendered by erb too, so your file could look something like this

{
    "first_name": <%= @user.first_name.to_json %>,
    "last_name": <%= @user.last_name.to_json %>
}

(edited Jan 23, 2023 to fix double-quoting on the values)

Community
  • 1
  • 1
erik
  • 6,406
  • 3
  • 36
  • 36
  • 9
    You might want to use `@user.first_name.to_json` instead of `escape_javascript`. There are some subtle differences between what JS allows and what is *strictly* JSON. (And those differences are becoming important as browsers implement their own JSON parsers.) – James A. Rosen Jan 18 '10 at 21:17
  • 1
    You should probably change the single quotes to double quotes, as JSON (unlike JS) only accepts double-quoted strings. – Abe Voelker Jan 20 '12 at 20:27
  • 1
    This is good, but you'll quickly find erb is a painful way to generate json. Check out my answer for some alternatives. – tybro0103 Oct 07 '13 at 15:09
  • I know this is an old answer, but it is completely wrong. to_json will return a formated json string "" already, so the resulting json will never be valid with extra quotes (""value""). Also, if user first name is nil, the resulting json will have the string "null" as the value. Also <%= uses html escaping which will mangle html characters in the input data. – d4n3 Sep 04 '15 at 09:19
  • I think you also need to remove quotes around `<%= xyz.to_json %>` otherwise you are left with extra quotes. – akostadinov Aug 23 '16 at 20:38
35

As others have mentioned you need a users/show.json view, but there are options to consider for the templating language...

ERB

Works out of the box. Great for HTML, but you'll quickly find it's awful for JSON.

RABL

Good solution. Have to add a dependency and learn its DSL.

JSON Builder

Same deal as RABL: Good solution. Have to add a dependency and learn its DSL.

Plain Ruby

Ruby is awesome at generating JSON and there's nothing new to learn as you can call to_json on a Hash or an AR object. Simply register the .rb extension for templates (in an initializer):

ActionView::Template.register_template_handler(:rb, :source.to_proc)

Then create the view users/show.json.rb:

@user.to_json

For more info on this approach see http://railscasts.com/episodes/379-template-handlers

tybro0103
  • 48,327
  • 33
  • 144
  • 170
  • 10
    Note that in rails 4, The .ruby template handler is registered by default https://github.com/rails/rails/commit/de1060f4e02925c12004f2 so you can skip registering .rb and name your file users/show.json.ruby. – Tim Diggins Aug 11 '15 at 11:13
  • 1
    Also, to update this further, json_builder has been superceded by https://github.com/rails/jbuilder. – Tim Diggins Aug 11 '15 at 11:15
27

RABL is probably the nicest solution to this that I've seen if you're looking for a cleaner alternative to ERb syntax. json_builder and argonaut, which are other solutions, both seem somewhat outdated and won't work with Rails 3.1 without some patching.

RABL is available via a gem or check out the GitHub repository; good examples too

https://github.com/nesquena/rabl

zapnap
  • 272
  • 3
  • 4
21

Just to update this answer for the sake of others who happen to end up on this page.

In Rails 3, you just need to create a file at views/users/show.json.erb. The @user object will be available to the view (just like it would be for html.) You don't even need to_json anymore.

To summarize, it's just

# users contoller
def show
  @user = User.find( params[:id] )
  respond_to do |format|
    format.html
    format.json
  end
end

and

/* views/users/show.json.erb */
{
    "name" : "<%= @user.name %>"
}
James Lim
  • 12,915
  • 4
  • 40
  • 65
  • 2
    I answered this 1.5 years ago. Nowadays I just use respond_with whenever I need JSON e.g. `respond_with @user, only: [:name]`. Refer to this [tutorial](http://bendyworks.com/geekville/tutorials/2012/6/respond-with-an-explanation) for more information. – James Lim May 24 '13 at 18:44
  • 2
    Just to add to this answer, this is actually dangerous for two reasons: it allows injection from user data because it doesn't escape newlines and backslashes, and also <%= html escapes the data so e.g. Sean O'Connor will have his name mangled to Sean O'Connor. – d4n3 Sep 04 '15 at 09:56
10

Just add show.json.erb file with the contents

<%= @user.to_json %>

Sometimes it is useful when you need some extra helper methods that are not available in controller, i.e. image_path(@user.avatar) or something to generate additional properties in JSON:

<%= @user.attributes.merge(:avatar => image_path(@user.avatar)).to_json %>
Priit
  • 5,200
  • 2
  • 21
  • 20
  • 8
    It would need to be `<%= raw(@user.to_json) %>` to avoid HTML escaping. What I do is that I rely on to_json as long as it gives me what I want, but when I want to do something else I template it with what is usually a `{ :blah => @user.the_blah }.to_json`. – clacke Nov 08 '11 at 07:51
6

This is potentially a better option and faster than ERB: https://github.com/dewski/json_builder

PETER BROWN
  • 550
  • 6
  • 14
1

Im new to RoR this is what I found out. you can directly render a json format

def YOUR_METHOD_HERE
  users = User.all
  render json: {allUsers: users} # ! rendering all users
END
aRtoo
  • 1,686
  • 2
  • 18
  • 38
0

I'm just starting out with RoR, my apologies if it's not what you're looking for. I found this and this might be the most up-to-date straightforward method as described in https://guides.rubyonrails.org/v5.1/layouts_and_rendering.html#using-render

2.2.8 Rendering JSON

You don't need to call to_json on the object that you want to render. If you use the :json option, render will automatically call to_json for you.

All you need to do in your action is this

respond_to do |format| 
        format.html
        format.atom
        format.json { render json: @user }
end 

And it renders your json response in ./users/1/custom_action.json

Marelons
  • 150
  • 6