I am trying to understand how I can expose my data in XML and JSON. I have made HTML views for the data now, but I don't understand much of the respond_to block and how you can respond with JSON and XML....and at the same time have control on the structure. Can somebody please help me with where I should start reading and learn how to do this? I haven't had much luck searching for it myself.
You can start by reading this guide. It gives a pretty good idea of how rendering works in rails.
This article is also very helpful.
I use the rabl gem to format the JSON I expose.
Your respond_to block for your users_controller#show action could look like:
respond_to do |format|
format.html
format.json
end
Then you can create a rabl template in /app/views/users/show.json.rabl:
object #user
attributes :id, :username, :first_name, :last_name
You can find more about rabl here
Related
On my project I have
respond_to :json
load_and_authorize_resource
def show
respond_with #job_pattern
end
as per tutorial here http://blog.plataformatec.com.br/2009/08/embracing-rest-with-mind-body-and-soul/
it works like this: when a request comes, for example with format xml, it will first search for a template at users/index.xml
so I checked for job_patterns/index.json but didnt find any file with this name
can anyone guide me where i can find the file or how the output is generated here if it is not with the file.
Because respond_to :json does not render a view, rather it calls render json: #job_pattern.
render json:#job_pattern calls #job_pattern.to_json and sets the JSON string as the response body. You can do the same with XML or YML.
This is an example of the rails convention over configuration philosophy - if there is a show.json.[erb|haml] it takes priority. Otherwise rails will look for an instance variable which corresponds with the name of the controller (#job or #jobs for index) and attempt to serialize it as JSON.
Further reading:
Justin Weiss: respond_to Without All the Pain
Rails Guides: Layouts and Rendering in Rails
In your case, your action is show so the template associated with is show.json in views/[namespace]/show.json.
You should create this template, or if this template is not found Rails will automatically invoke to_json on the object passed to respond_with.
Refer to documentation.
Recents version of Rails with generated scaffold use show.json.jbuilder as template file.
For more info about it:
jbuilder
I need a pretty output of the JSON for an activerecord object in the rails controller. Based on the answer to this question by jpatokal, I tried the following:
respond_to do |format|
format.json { render :json => JSON.pretty_generate(record) }
end
where
record
is an activerecord object. It does not produce a prettified output. However, when I try outputting a hash using the same code, viz,
respond_to do |format|
format.json { render :json => JSON.pretty_generate({"abc" => "1", "def" => "2"}) }
end
it does produce a prettified output (so pretty_generate is working, and so is my browser).
How do I use pretty_generate to produce a pretty output of an activerecord object?
To get pretty output of JSON from an active record object you have to first request the object as JSON.
record.as_json
The above code will do this for you, the short way to render out pretty JSON from the controller is:
render json: JSON.pretty_generate(record.as_json)
This also solves the "only generation of JSON objects or arrays allowed" error you can get trying to convert AR objects to pretty_generate JSON.
EDIT: I forgot to mention this can all be done in rails 4.1.8 and above (possibly even earlier) using the standard json and multi-json gems packaged with rails project.
I'm building an API on Rails using ActiveRecordSerializer for serialization. When I want to render a list of resources I use:
render json: #resources
This automatically detects that there is a serializer for the resource, and uses it.
Now I want to implement pagination, and my idea is having a class called PaginatedResponse, instantiate it and render it as a json like this:
render json: PaginatedResponse.new(#resources, <more meta information of the page>)
The problem is that when I use this, everything works well but the resources are not rendered using ActiveRecordSerializer, but a default serializer. I suspect that this is happening because PaginatedResponse does not extend ActiveRecord.
Any clue how can I solve this?
Rails 4 has introduced a new concept jbuilder by default. So just create index.json.jbuilder and put the json syntex based code. Just refer the default scaffold index json jbuilder below,
json.array!(#users) do |user|
json.extract! user, :name, :email, :phone, :native_place
json.url user_url(user, format: :json)
end
This is for rendering all users with his name, phone, native_place.
So remove the line
render json: #resources
from your code and implement the the new jbuilder concept.
The solution was including ActiveModel::SerializerSupport in PaginatedResponse to indicate ActiveRecordSerializer that a serializer should be used.
I'm really confused on the concept of this.
I'm supposed to make API that handles JSON responses. I read this
and other places, they all showed example on how to do it for the show or index aspect of the controller. I understand that, where you outputs all the attributes of the model. But my main question is, if somebody were to create or edit, what do I do with the whole JSON on there?
If all you need to do is pass back a 200 for a successfull create, then don't creating a response.
render :nothing => true
If on the other hand, you added some important information to the object that you are updating that the client will require (If you are not sure, then assume that the client will require it), then you should pass the updated object's attributes back
respond_to do |format|
format.json {render :json => {... }}
end
I have a situation where I'm returning json objects to my application which are built from YML files. Because to parse the yml file and return it as json I always have to do something like this:
format.json { render json: YAML.load(render_to_string :file => File.join(Rails.root,'app','views','home','icons.yml.erb'), :layout => false ) }
I would like to make this operation shorter, by creating a custom format that (however) result in a json, so I don't want to create a new mime type.
My idea is to write:
format.myformat
Which will automatically search for myaction.myformat.erb inside views/mycontroller directory, and will automatically parse the yaml file returning it as a json object.
Is this possible? If yes, how can I eventually do this?
Edit 1:
I found an important suggestion in config/mime_types.rb:
Mime::Type.register_alias "text/html", :iphone
So I can alias a mime type, now the biggest problem is: how to define the default render action for a given format, like format.html does?
If I write
format.html
current_action.html.erb will be automatically rendered, how can I choose the correct method to render a custom format?
Edit 2:
I managed to create this code (inside a controller, through some helper methods I built):
def icons
respond_to do |format|
format.extjson { render_to_extjson }
end
end
Is possible to make rails understand that if I write:
def icons
respond_to do |format|
format.extjson
end
end
it has to do:
format.extjson { render_to_extjson }
by default?
You could do something like:
respond_to do |format|
format.html { #foo = Foo.all(:limit => 10) }
format.any(:atom, :rss) { #foo = Foo.all }
end
A longer post going into the guts of the render actions can be found here: http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to/
While Josh's answer is a valid one, I would rather see your parsing code wrapped up into an object. If you put that object into app/models, it'll be testable and you can always verify any change to the logic with a test suite.
Another upside to this is that you can re-use the format.json call and make you controller that much simpler.
This is not doable at the moment, I read a lot of rails sources and there isn't a way to access that method, so isn't possible to customize it.
I'll write a rails plugin to support this and eventually I'll post it here, but for sure the answer actually is: this can't be done.