Languages

Fsharp
ActionScript
xBase
Clean
GPSS
PureBasic
Sieve
Erlang
JOVIAL
Mercury
Linda
DataFlex
PostScript
FoxPro2
VFP
Cobol
Prolog
Jython
Awk
VisualBasic
JavaScript
Matlab
ASP
Haskell
Csharp
D
Smalltalk
Nemerle
Pixilang
Java
SQL
Python
ObjectPascal
Ruby
Perl
Pascal
Assembler
PHP
C
Functions  Add function  Users  Registration  Enter   About  ASCII Table  Our helpers

Ruby-on-Rails


1 Options for Web Applications with Ruby on Rails

2 15.5 Displaying Templates with Render

3 15.6 Integrating a Database with Your Rails Application

4 15.7 Understanding Pluralization Rules

15.5 Displaying Templates with Render



(Page 2 of 4 )

Problem

Railss default mapping of one action method to one view template is not flexible enough for you. You want to customize the template that gets rendered for a particular action by calling Rails_s rendering code directly.

Solution

Rendering happens in the ActionController::Base#render method. Rails_s default behavior is to call render after the action method runs, mapping the action to a corresponding view template. The foo action gets mapped to the foo.rhtml template.

You can call render from within an action method to make Rails render a different template. This controller defines two actions, both of which are rendered using the shopping_list.rhtml template:

  class ListController < ApplicationController
   
def index
     
@list = [_papaya_, _polio vaccine_]
      render :action => _shopping_list_
   
end

    def shopping_list
      @list = [_cotton balls_, _amino acids_, _pie_]
    end
  end

By default, render assumes that you are talking about the controller and action that are running when render is called. If you call render with no arguments, Rails will work the same way it usually does. But specifying _shopping_list_ as the view overrides this default, and makes the index action use the shopping_list.rhtml template, just like the shopping_list action does.

Discussion

Although they use the same template, visiting the index action is not the same as visiting the shopping_list action. They display different lists, because index defines a different list from shopping_list.

Recall from Recipe 15.4 that the redirect method doesn_t perform an immediate HTTP redirect. It tells Rails to do a redirect once the current action method finishes running. Similarly, the render method doesn_t do the rendering immediately. It only tells Rails which template to render when the action is complete.

Consider this example:

  class ListController < ApplicationController
   
def index
     
render :action => _shopping_list_
     
@budget = 87.50
   
end

    def shopping_list
      @list = [_lizard food_, _baking soda_]
    end
  end

You might think that calling index sets @list but not @budget. Actually, the reverse is true. Calling index sets @budget but not @list.

The @budget variable gets set because render does not stop the execution of the current action. Calling render is like sealing a message in an envelope that gets opened by Rails at some point in the future. You_re still free to set instance variables and make other method calls. Once your action method returns, Rails will open the envelope and use the rendering strategy contained within.

The @list variable does not get set because the render call does not call the shopping_ list action. It just makes the existing action, index, use the shopping_list.rhtml template instead of the index.rhtml template. There doesn_t even need to be a shopping_list action: there just has to be a template named shopping_list.rhtml.

If you do want to invoke one action from another, you can invoke the action method explicitly. This code will make index set both @budget and @list:

  class ListController < ApplicationController
    def index
      shopping_list and render :action => _shopping_list_
      @budget = 87.50
    end
 
end

Another consequence of this "envelope" behavior is that you must never call render twice within a single client request (the same goes for render_s cousin redirect_to, which also seals a message in an envelope).

If you write code like the following, Rails will complain. You_re giving it two sealed envelopes, and it doesn_t know which to open:

  class ListController < ApplicationController
   
def plain_and_fancy
     
render :action => _plain_list_
     
render :action => _fancy_list_
   
end
  end

But the following code is fine, because any given request will only trigger one branch of the if/else clause. Whatever happens, render will only be called once per request.

  class ListController < ApplicationController
    def plain_or_fancy
      if params[:fancy]
        render :action => _fancy_list_
      else
        render :action => _plain_list_
      end
    end
  end

With redirect_to, if you want to force your action method to stop running, you can put a return statement immediately after your call to render. This code does not set the @budget variable, because execution never gets past the return statement:

  class ListController < ApplicationController
   
def index
     
render :action => _shopping_list_ and return
     
@budget = 87.50     # This line won_t be run.
   
end
  end

See Also

  • Recipe 15.4, "Redirecting to a Different Location"
  • Recipe 15.14, "Refactoring the View into Partial Snippets of Views," shows examples of calling render within a view template
1 2 3 4
Acrobatic Robots

Dennis Hong is living his dreams ... literally ... in a lab filled with wacky robots

Full story at http://www.nsf.gov/news/special_reports/science_nation/acrobaticrobots.jsp?WT.mc_id=USNSF_51


This is an NSF News item.

PycckaR
BepcuR


Articles
Articles


Library
Library


Downloads
Downloads

Google Chrome Golf 6
 © Internet, books, teachers and Rudevich Alexander brains.