Rendering Actions

Problem

You have an action that has gathered some data from your model, perhaps based on a user-defined query, and you want to render another action to display the results.

Solution

Use render :action => 'action_name', where action_name is the name of the action that displays the result. The search method in CategoriesController does just that:

app/controllers/categories_controller.rb:

class CategoriesController < ApplicationController
 def search_form
 end
 def search 
 @categories = Category.find(:all,
 :conditions => 
 ["name like ?", "%#{params[:cat]}%"])
 if @categories
 render :action => 'search_results'
 else 
 flash['notice'] = 'No Category found.'
 render :action => 'search_form'
 end
 end
 def search_results
 @category = Category.find(params[:id])
 end end

Discussion

In the solution, if the find call in search action successfully returns a category, the search_results action is rendered. At that point, Rails looks for a template file named after that action, under a directory named after the controller, i.e., app/views/categories/search_results.rhtml.

This is probably the most common pattern of control flow in Rails: you perform a query, or some other immutable action, and then you display the results of that action with a second action. Ideally, these actions are separate because they do distinctly different tasks (the first allows the user to make a query; the second displays the results), and combining the two actions into a single method inhibits code reuse.

The solution calls render only once, whether or not a category is found in the database. It's possible to render an action that renders another action, and so on, but you'll get a DoubleRenderError if you try to render twice within the same action. Rails 0.13 added this error message to help avoid confusing side effects of parallel render attempts.

An action can continue processing after a call to render, but it usually makes more sense to call render at the end of the action (just before the return statement, if there is one). This way, the rendered action can communicate success or failure to the user.

Rails renders actions within the layout that is associated with the action's controller. You can optionally render with no layout by specifying :layout=>false:

render :action => "display", :layout => false

Or you can specify another layout by supplying the name of that layout:

render :action => "display", :layout => "another_layout" 

See Also