Rails: respond_to JSON and HTML - ruby-on-rails

I have a controller "UserController" that should respond to normal and ajax requests to http://localhost:3000/user/3.
When it is a normal request, I want to render my view. When it is an AJAX request, I want to return JSON.
The correct approach seems to be a respond_to do |format| block. Writing the JSON is easy, but how can I get it to respond to the HTML and simply render the view as usual?
def show
#user = User.find(params[:id])
respond_to do |format|
format.html {
render :show ????this seems unnecessary. Can it be eliminated???
}
format.json {
render json: #user
}
end
end

As per my knowledge its not necessary to "render show" in format.html it will automatically look for a respective action view for ex : show.html.erb for html request and show,js,erb for JS request.
so this will work
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
also, you can check the request is ajax or not by checking request.xhr? it returns true if request is a ajax one.

Yes, you can change it to
respond_to do |format|
format.html
format.json { render json: #user }
end

The best way to do this is just like Amitkumar Jha said, but if you need a simple and quick way to render your objects, you can also use this "shortcut":
def index
#users = User.all
respond_to :html, :json, :xml
end
Or make respond_to work for all the actions in the controller using respond_with :
class UserController < ApplicationController
respond_to :html, :json, :xml
def index
#users = User.all
respond_with(#users)
end
end
Starting from Rails 4.2 version you will need to use gem responder to be able to use respond_with.
If you need more control and want to be able to have a few actions that act differently, always use a full respond_to block. You can read more here.

Related

ActionController::UnknownFormat in CoinsController#index

In my CoinsController, I have added a respond_to method in my index controller. I'm not sure if my code is right but here is my index controller below:
def index
paginated = paginate(Coin.recent)
render_collection(paginated)
respond_to do |format|
format.json do
format.html # index.html.erb
format.json { render json: render_collection(paginated) }
end
end
end
I read the few documents I found online about respond_to do |format| method and when I tried adding it manually the way it is in the documentation, I get an Unknown Format error. What I'm trying to do is have logic that handles both html and json, so that it can act as a json api and a view renderer.
Any ideas?
Ok guys so I found out the solution to my problem:
def index
paginated = paginate(Coin.recent)
# render_collection(paginated)
respond_to do |format|
format.json do
render_collection(paginated)
end
format.html do
render :index
end
end
end
I had commented out the render_collection(paginated) and then added json and html to it's own block and it worked.

Change filename of js for eg show.js to show2.js in respond_to

I have one js file show.js that is renderd for the action def show:
def show
....
respond_to do |format|
format.html
format.js
end
end
My question is how can I change the respond_to block, so that it does not respond with show.js but for example with newshow.js? I ask because I would like to render different js dependent on the params! Thanks! I use Rails 4.
I believe that this one would work:
respond_to do |format|
format.html
format.js { render :newshow }
end

What does respond_to do when called without a block?

I understand how respond_to works when it's called with something like this:
def index
#users = User.all
respond_to do |format|
format.html
format.json { render json: #users }
end
end
But I've seen some apps which pass respond_to a list of symbols, outside of the controller methods, e.g.:
class UsersController < ApplicationController
respond_to :html, :json
def index
# blah blah bah
end
end
What does this do? I've been playing around with it in one of my controllers and I can't figure out what difference it makes.
For a given controller action, #respond_with generates an appropriate response based on the mime-type requested by the client.
If the method is called with just a resource, as in this example -
class PeopleController < ApplicationController
respond_to :html, :xml, :json
def index
#people = Person.all
respond_with #people
end
end
then the mime-type of the response is typically selected based on the request's Accept header and the set of available formats declared by previous calls to the controller's class method respond_to. Alternatively the mime-type can be selected by explicitly setting request.format in the controller.
If an acceptable format is not identified, the application returns a '406 - not acceptable' status. Otherwise, the default response is to render a template named after the current action and the selected format, e.g. index.html.erb. If no template is available, the behavior depends on the selected format:
for an html response - if the request method is get, an exception is raised but for other requests such as post the response depends on whether the resource has any validation errors (i.e. assuming that an attempt has been made to save the resource, e.g. by a create action) -
If there are no errors, i.e. the resource was saved successfully, the response redirect's to the resource i.e. its show action.
If there are validation errors, the response renders a default action, which is :new for a post request or :edit for patch or put.
Thus an example like this -
respond_to :html, :xml
def create
#user = User.new(params[:user])
flash[:notice] = 'User was successfully created.' if #user.save
respond_with(#user)
end
is equivalent, in the absence of create.html.erb, to -
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = 'User was successfully created.'
format.html { redirect_to(#user) }
format.xml { render xml: #user }
else
format.html { render action: "new" }
format.xml { render xml: #user }
end
end
end
for a javascript request - if the template isn't found, an exception is raised.
for other requests - i.e. data formats such as xml, json, csv etc, if the resource passed to respond_with responds to to_, the method attempts to render the resource in the requested format directly, e.g. for an xml request, the response is equivalent to calling render xml: resource.

Respond_to and redirect in the same action in Rails

In the Update action of Rails controllers usually there is code that looks like this:
def update
#book = Book.find(params[:id])
if #book.update_attributes(params[:book])
redirect_to(#book)
else
render :edit
end
end
In the else case, this will render the edit template. But what if I wanted to use a respond_to, exactly the same way that I have in the edit action, as:
def update
#book = Book.find(params[:id])
if #book.update_attributes(params[:book])
redirect_to(#book)
else
respond_to do |format|
format.html # edit.html.erb
format.json { render :json => #team }
end
end
end
So, if the Update fails, be sure you are returning a json or html depending on the requested format. Does that makes sense? If so, how would you avoid the error: "Render and/or redirect were called multiple times in this action"
Makes sense to me. The answer should be simple, just return after redirect_to.
def update
#book = Book.find(params[:id])
if #book.update_attributes(params[:book])
redirect_to(#book)
return
else
respond_to do |format|
format.html # edit.html.erb
format.json { render :json => #team }
end
end
end
Not sure exactly how you're rendering multiple times, but assuming you are, a well-placed return should tell RAILS to stop processing any further renders after redirecting. If that's all true, it's likely that there's an after_filter interfering from somewhere.

Add JSON support to Rails app

I am experimenting with Rails and was wondering what's needed to allow/add support for JSON requests?
I have a vanilla installation of Rails 2.3.5 and the default scaffolding seem to provide support for HTML & XML requests but not JSON.
class EventsController < ApplicationController
# GET /events
# GET /events.xml
def index
#events = Event.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #events }
end
end
# GET /events/1
# GET /events/1.xml
def show
#event = Event.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #event }
end
end
...
I'm new to this but it would appear as though i would need to add a format line in each method along the lines of:
format.js { render :js => #event.json }
couldn't this be done automatically? perhaps there's a template somewhere i need to update...or a flag i can set? Or perhaps, and most likely, I've missed the boat entirely?!?
You do:
format.json {render :json=>#event}
That will render the default activerecord JSON for the model
The option of ease of use is that you can write a private method which takes the format object and an object to render and then, based on the format, renders different things. Example:
class MyController<ApplicationController
def show
#event=Event.find(params[:id])
respond_to do {|format| myRenderer(format,#event)}
end
...
private
def myRenderer(fmt,obj)
fmt.json {render :json=>obj}
fmt.html
fmt.xml {render :xml=>obj}
end

Resources