I have seen some people using code like this
respond_to do |format|
format.html
format.js
end
What is the purpose of this if we have template.html and template.js. Either can be rendered without specifying respond_to
Your snippet doesn't do anything special, but the formatting options allow you to provide additional custom behavior if it is necessary.
For example, if you want to render your #products as a JSON:
respond_to do |format|
format.html
format.js { render :json => #products }
end
This is just one of the many things you can do with the format blocks. For more information, see Ruby on Rails Guides: Layouts and Rendering
The format options can take a block so that you can do some custom rendering such as rendering a file or :head response. Have a look at some of the examples here
If you don't specify different behavior for the different formats there is no reason to use respond_to. If you have templates they will automatically be picked up by rails. The respond_to method is useful if you need different behavior per format:
respond_to do |format|
format.html { render :edit }
format.json { render :json => '{}' }
end
Related
I have a Rails controller which provides both HTML and PDF responses, and thus I have view.pdf.haml and view.html.haml files. These are either identical or extremely close to identical.
How can I have Rails use a single view for multiple formats?
You can specify what format to render with :formats option:
# Both will render view.html.haml
respond_to do |format|
format.html { render :view }
format.pdf { render :view, formats: :html }
end
https://guides.rubyonrails.org/layouts_and_rendering.html#the-formats-option
Do you mean have the same action serve up different resource types - i.e. both a web page and a PDF? If I understand the problem, you can use the respond_to method.
def show
#object = Object.find params[:id]
respond_to do |format|
format.html
format.pdf { ..code to render the pdf.. }
end
end
That ..code to render the pdf.. is the tricky part. There are PDF gems that support inline rendering, but you may end up using send_data or similar to set a file name, disposition, etc and deliver the PDF document to the end user.
Rails scaffold generated the following:
respond_to do |format|
if #student.save
format.html { redirect_to #student, notice => 'Student was successfully created.' }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
After reading this I understand how the respond_to is working (sort of), but I don't get what format is doing. Shouldn't it be either format.html or format.json and not both? What are these two lines actually doing?
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
Is there an implied if in there? Is it something like
if (format == html) {}
if (format == json) {}
Side note: Why does update require the respond_to block while show will handle /students/1.json or /students/1 without any logic at all?
format is a local variable that respond_to yields. When you do format.html {} you are actually registering a callback block for a format.
Rails goes through the registered formats and tries to find a compatible format to the MIME type in the request. If there is no handler it will raise an error.
This could be explained as something like using syntactic sugar on top of a case statement (the Ruby equivalent of a switch statement). But the analogy is not completely accurate since Rails does a bit of work in matching the request type.
Also the code inside your block is not executed when the format.html block is registered (as it would be if it was just a conditional statement) but rather when respond_to finishes or not at all if you are using for example E-Tag caching.
Why does update require the respond_to block while show will handle
/students/1.json or /students/1 without any logic at all?
Rails handles many actions by using a convention over configuration approach and guessing the intent of the action.
def PostsController < ApplicationController
def index
# rails auto-magically fills in the controller with something
# like this
#posts = Post.all
respond_to do |format|
format.html { render :index }
format.json { render json: #posts }
end
end
def show
# convention over configuration is awesome!
#post = Post.find(params[:id])
respond_to do |format|
format.html { render :show }
format.json { render json: #post }
end
end
def new
#post = Post.new
render :new
end
def edit
#post = Post.find(params[:id])
render :edit
end
end
Rails assumes that there is a resource with the same name as the controller and auto-magically fills in the controller action. It also assumes there is a view in app/views/posts/(:action).html.[erb|haml|slim|jbuilder]. This is known as implicit rendering.
The comments show roughly what action rails attempts.
It does not fill in actions which operate on data (create, update, destroy) since the actual implementation can vary greatly and it's hard to make useful guesses.
Well, it depends on the format of the request. If a request demands HTML from the server, format.html block will be executed, and in the same way, if a request demands JSON format, format.json will be executed.
Rails will automatically(read: magically) handle the if (format == html) part for you. All you have to do is fill in the blanks. Same way, you can write a block for XML starting with format.xml.
And for the side note, I think you have said it otherwise. update method doesn't require respond_to block, while show requires. And the reason is very simple: update method is there to update the Model, and then, redirect you to somewhere, while show will always return you something. In your case, /students/1 will return you the first student created in the database, and the response will be HTML, while /students/1.json will return you the same result, but response will be JSON this time.
Well you could very well replace 'format' with 'foo' or 'banana' or whatever you want. It is just the variable name in this case because the variable that is sent to your block by respond_to is passing along the format as requested by the incoming http request's Accept header.
Sometimes you'll see 422 "Unacceptable" errors in your logs because you are receiving a request with an Accept header that does not request a mime type your app knows about.
As it is, your callers should be using a browser or be a JSON consumer sending the proper headers to receive responses from the boilerplate.
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.
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
I'm a newcomer to Rails, and have been following the tutorial on the rails webpage.
Using the scaffold instruction to create a "post" model, I found that the new action in the controller has a special directive for XML format:
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #post }
end
end
I can't see the reasoning for supporting an XML request when creating a new post. Browsing to /posts/new.xml returns nothing. What is the purpose of this?
The reasoning for it behind the new action is simply to provide a xml client with the default data (or something else if you want).
The format directive is being used by all routes, and you don't need to support a format unless you want to.
The above code could might as well have looked like:
respond_to do |format|
format.html # renders new.html.erb
format.xml { render :xml => {:message => "XML is not supported"} }
format.json { render :text => #post.to_jsonĀ }
format.js # renders new.js.erb
end
Also, this is not limited to the new action, but is available in all your actions. The format to use is either taken from the url (if the route is set up to use it), or from the HTTP-Accept header that the browser sends.