What is the advantage of using respond_to
in Rails instead of a case statement? I have several instance variables that I want to set same way for some formats, but not for HTML. This does not seem to work:
respond_to do |format|
format.html do
# ...
end
format.any(:csv, :xml) do
# common stuff
end
format.csv do
# ...
end
format.xml do
# ...
end
end
I think I'll end up using a couple of case request.format
and not using respond_to
at all:
case request.format
when 'html'
# ...
when 'csv', 'xml'
# common stuff
end
# more common stuff
case request.format
when 'html'
# render
when 'csv'
# custom render csv
when 'xml'
# render xml with a template
end
So I wonder what is a good use case for respond_to
, where case request.format
wouldn't look better?
respond_to
is not just a way to find out what type of response the client expected but also a way to tell rails
what type of response you are willing to provide.
For example a simple scenario where we have this controller:
class SimpleController < ApplicationController
def index
respond_to :html, :json
end
end
A client sends a request expecting xml response
curl -H "Accept: application/xml" \
-H "Content-Type: application/xml" \
-X GET "host:port/simple/index"
Rails will response with 406
Completed 406 Not Acceptable in 0ms (ActiveRecord: 0.0ms)
However, if you simply filter request.format
using case
like in your example the client will receive a 500
error because rails
cannot find a corresponding template to the request format.
Of course you can also call respond_to
on class level as well as specify respond format in routes.rb
Dive into rails
source code and api documentation if you want to get more in-depth explanation to this.
First of all, the reason the respond_to
block does not work is because you are using format.any(:csv, :xml)
in conjunction with format.csv
. You can only use one of these.
This should be a clear indication that you are trying to do too much in your controller. For example, if you are doing common stuff for csv
and xml
responses, then maybe you should create a class in your lib directory:
# lib/foo_serializer.rb
class FooSerializer
def initialize(bar)
@bar = bar
end
def do_stuff
@bar.to_s
end
end
And then call one of its method for each type of response:
respond_to do |format|
format.html do
# ...
end
format.csv do
FooSerializer.new(data).do_stuff
# ...
end
format.xml do
FooSerializer.new(data).do_stuff
# ...
end
end
The respond_to
syntax:
Is part of the standard Rails Way™
Takes care of rendering the correct file
Not only looks better but is also more maintainable
You should try to stick with it.
The request.format
field can be useful where the respond_to
block is not appropriate.
For example, I'm using the sunspot gem for searching, and my controller looks like this:
def index
case request.format
when 'xlsx'
per_page: Person.count
when 'html'
per_page: 30
end
@search = Person.search do
with :name, params[:name]
fulltext params[:search_term]
paginate page: params[:page], per_page: per_page
end
@people = @search.results
respond_to do |format|
format.xlsx {send_file @people.to_xlsx, filename: 'people.xlsx'}
format.html
end
end
I've been working with Rails for a while, and I've always seen respond_to in this form:
respond_to do |format|
format.js
format.html # index.html.erb
format.xml { render :xml => @posts }
end
I don't know where you would've seen something with the nested do's.
EDIT:
For pagination, see
https://github.com/mislav/will_paginate
EDIT 2:
format.html { render :html => Post.paginate(:page => params[:page]) }
or something like that.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.