views:

193

answers:

3

I often use

respond_to do |format|
...
end

in Rails for my Restful actions, but I don't know what the ideal solution is for handling various forms of, say, html responses. For instance, view1 that calls action A might expect back html with a list of widgets wrapped in a UL tag, while view2 expects the same list of widgets wrapped in a table. How does one Restfully express that not only do I want back an html formatted response, but I want it wrapped in a table, or in a UL, OL, options, or some other common list-oriented html tag?

A: 

I think that you are on the wrong track here. First of all views don't call actions, it's the other way around. Second, respond_to is used to display completely different format (i.e. html, xml, js, etc.) not a different template.

Slobodan Kovacevic
+1  A: 

This is the basic idea:

Controller

class ProductsController < ApplicationController

  def index

    # this will be used in the view
    @mode = params[:mode] || 'list'

    # respond_to is used for responding to different formats
    respond_to do |format|
      format.html            # index.html.erb
      format.js              # index.js.erb
      format.xml do          # index.xml.erb
        # custom things can go in a block like this
      end
    end
  end

end

Views

<!-- views/products/index.html.erb -->
<h1>Listing Products</h1>

<%= render params[:mode], :products => @products %>


<!-- views/products/_list.html.erb -->
<ul>
  <% for p in products %>
  <li><%= p.name %></li>
  <% end %>
</ul>


<!-- views/products/_table.html.erb -->
<table>
  <% for p in products %>
  <tr>
    <td><%= p.name %></td>
  </tr>
  <% end %>
</table>

Usage:

You can link to other views "modes" using:

<%= link_to "View as list",   products_path(:mode => "list") %>
<%= link_to "View as table",  products_path(:mode => "table") %> 

Note: You'll want to do something to ensure that the user doesn't attempt to specify an invalid view mode in the URL.

macek
Thanks for the response. Yeah, I follow you on the use of an additional parameter. I'm (perhaps, wishfully) hoping to find a "more Restful" solution. One that doesn't require hanging additional params off the end of the URL. Just wondered what others are doing...
lukewendling
macek
A: 

Examine this variant of the default route:

 map.connect ':controller/:action/:id.:format'

Note that it allows you to set the format by passing it in as the extension. I sometimes have applications with multiple consumers that require different XML formats, for example.

So, for example in once place the iphone app uses format 'xmlm' (for XML Mobile) and a java consumer uses 'xml' because it's working with the full serialization. This lets me use that indicator as a top-level format.

respond_to do |format|
 format.xml{  render :xml => @people.to_xml  }
 format.xmlm { do other stuff }
end

This page will be of help to you and contains all the information neccesary to implement this stuff (note particularly the part about custom mime types), make sure to check out the comments: http://apidock.com/rails/v2.3.4/ActionController/MimeResponds/InstanceMethods/respond_to

corprew
Hi... so, it's not different formats that I'm going for, it's different renderings within the same format. So, with html rendering, sometimes I might want to render a list of widgets in a table, at other times, render them in an UL, or maybe as a list of option tags to populate a select tag.
lukewendling
cool. i've been conceptualizing 'different renderings within the same format' as different formats in the stuff that i've been doing. good luck!
corprew