14

In one of my rails controller, I must respond to several types of formats, so I use the typical respond_to chain:

respond_to do |format|
  format.html   { ... }
  format.mobile { ... }
  format.jpg  { ... }
  format.xml  { ... }
  format.js   { ... }
end

Usually that the { ... } part is repeated on several formats. What is the best way to stay DRY on this case? On an scenario in which html, mobile and xml have a "repeated" action, I'd like to do something like this:

respond_to do |format|
  format[:html, :mobile, :xml] { ... }
  format.jpg  { ... }
  format.js   { ... }
end

Thanks a lot.

kikito
  • 51,734
  • 32
  • 149
  • 189
  • As a side note, I've browsed the respond_to api(http://api.rubyonrails.org/classes/ActionController/MimeResponds/InstanceMethods.html). It says respond_to takes parameters, as well as a block. Maybe the solution is there? – kikito Feb 03 '10 at 18:05

2 Answers2

21

Have you tried format.any(:html, :mobile, :xml)?

Example (added 2011/9/14)

From the rails doc

Respond to also allows you to specify a common block for different formats by using any:

def index
  @people = Person.all

  respond_to do |format|
    format.html
    format.any(:xml, :json) { render request.format.to_sym => @people }
  end
end

In the example above, if the format is xml, it will render:

render :xml => @people

Or if the format is json:

render :json => @people
Eric Hu
  • 18,048
  • 9
  • 51
  • 67
raf
  • 310
  • 2
  • 10
  • I had the opportunity to attack this problem again recently. This solution works! So it is now the best answer. Updating (sorry jonnii) – kikito Mar 30 '10 at 16:44
  • nice to know my answer was useful! see you around here – raf Mar 31 '10 at 01:35
5

Can you give an example of the repetition you're seeing?

You could always do something like this:

respond_to do |do|
  format.html { common_stuff }
  format.mobile { common_stuff }
  format.xml { common_stuff }
  ...
end

protected 

def common_stuff
  ...
end

I think something like that could be refactored to (I probably got this wrong as I always forget how to use a method as a block:

[:html, :mobile, :xml].each { |f| format.send(:f, lambda{ common_stuff }) }

Having said that, I think you're better off with the former as it's more explicit.

jonnii
  • 28,019
  • 8
  • 80
  • 108
  • I ended up using a common function. It looks simpler than the lambda stuff. Thanks for sharing this. – kikito Feb 05 '10 at 08:35