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 Handling Cookies and DHTML Effects with Ruby on Rails

2 15.13 Extracting Code into Helper Functions

3 15.14 Refactoring the View into Partial Snippets of Views

4 15.15 Adding DHTML Effects with script.aculo.us

15.14 Refactoring the View into Partial Snippets of Views



(Page 3 of 4 )

Problem

Your view doesn_t contain a lot of Ruby code, but it_s still becoming more complicated than you_d like. You_d like to refactor the view logic into separate, reusable templates.

Solution

You can refactor a view template into multiple templates called partials. One template can include another by calling the render method, first seen in Recipe 15.5.

Let_s start with a more complex version of the view shown in Recipe 15.5:

  <!-- app/views/list/shopping_list.rhtml
-->
  <h2>My shopping list</h2>

  <ul>
  <% @list.each do |item| %>
   <li><%= item.name %> - 
    <%= link_to _Delete_, {:action => _delete_, :id => item.id},
                  :post => true %>
   
</li>
  <% end %>
  </ul>

  <h2>Add a new item</h2>

  <%= form_tag :action => _new_ %>
   Item: <%= text_field "product", "name"
%>&#x00A;
   <%= submit_tag "Add new item" %>
 
<%= end_form_tag %>

Here_s the corresponding controller class, and a dummy ListItem class to serve as the model:

  # app/controllers/list_controller.rb
  class ListController < ActionController::Base
    def shopping_list
      @list = [ListItem.new(4, _aspirin_), ListItem.new(199, _succotash_)]
    end

    # Other actions go here: add, delete, etc.
    # ...
  end

  class ListItem
    def initialize(id, name)
      @id, @name = id, name
    end
  end

The view has two parts: the first part lists all the items, and the second part prints a form to add a new item. An obvious first step is to split out the new item form.

We can do this by creating a partial view to print the new item form. To do this, create a new file within app/views/list/ called _new_item_form.rhtml. The underscore in front of the filename indicates that it is a partial view, not a full-fledged view for an action called new_item_form. Here_s the partial file.

  <!-- app/views/list/_new_item_form.rhtml -->

  <%= form_tag :action => _new_ %>
  Item: <%= text_field "item", "value" %>&#x00A;
  <%= submit_tag "Add new item" %>
  <%= end_form_tag %>

To include a partial, call the render method from within a template. Here is the _new_ item_form partial integrated into the main view. The view looks exactly the same, but the code is better organized.

  <!-- app/views/list/shopping_list.rhtml
-->
  <h2>My shopping list</h2>

  <ul>
  <% @list.each do |item| %>
   <li><%= item.name %> -
    <%= link_to _Delete_, {:action => _delete_, :id => item.id},
                :post => true %>
  
</li>
  <% end %>
  </ul>
 
<%= render :partial => _new_item_form_ %>

Even though the filename starts with an underscore, when you call the partial, you omit the underscore.

Discussion

Partial views inherit all the instance variables provided by the controller, so they have access to the same instance variables as the parent view. That_s why we didn_t have to change any of the form code for the _new_item_form partial.

We can create a second partial to factor out the code that prints the <LI> tag for each list item. Here_s _list_item.rhtml:

  <!-- app/views/list/_list_item.rhtml -->
  <li><%= list_item.name %> -
  <%= link_to _Delete_, {:action => _delete_, :id => list_item.id},
             
:post => true %>
  </li>

And heres the revised main view:

  <!-- app/views/list/shopping_list.rhtml
-->
  <h2>My shopping list</h2>

  <ul>
  <% @list.each do |item| %>
   
<%= render :partial => _list_item_, :locals => {:list_item => item} %>
  <% end %>
  </ul>

  <%= render :partial => _new_item_form_ %>

Partial views do not inherit local variables from their parent view, so the item variable needs to be passed in to the partial, in a special hash called :locals. It_s accessible in the partial as list_item, because that_s the name it was given in the hash.

This scenario, iterating over an Enumerable and rendering a partial for each element, is very common in web applications, so Rails provides a shortcut. We can simplify our main view even more by passing our array into render (as the :collection parameter) and having it do the iteration for us:

  <!-- app/views/list/shopping_list.rhtml
-- >
  <h2>My shopping list</h2>

  <ul>
   
<%= render :collection => @list, :partial => _list_item_ %>
  </ul>

  <%= render :partial => _new_item_form_ %>

The partial is rendered once for every element in @list. Each list element is made available as the local variable list_item. In case you haven_t guessed, this name comes from the name of the partial itself: render automatically gives _foo.rhtml a local variable called foo.

list_item_counter is another variable that is set automatically (again, the name mirrors the name of the template). list_item_counter is the current item_s index in the collection undergoing iteration. This variable can be handy if you want alternating list items to show up in different styles:

  <!-- app/views/list/_list_item.rhtml -- >
  <li><%= list_item.name %> -
  <% css_class = list_item_counter % 2 == 0 ? _a_ : _b_ %>
  <%= link_to _Delete_, {:action => _delete_, :id => list_item.id},
              {_class_ => css_class}, :post => true %>
  </li>

When there_s no collection present, you can pass a single object into a partial by specifying an :object argument to render. This is simpler than creating a whole hash of :locals just to pass one object. As with :collection, the object will be made available as a local variable whose name is based on the name of the partial.

Here_s an example: we_ll send the shopping list into the new_item_form.rhtml partial, so that the new item form can print a more verbose message. Here_s the change to shopping_list.rhtml:

  <%= render :partial => _new_item_form_, :object => @list %>

Here_s the new version of _new_item_form.rhtml:

  <!-- app/views/list/_new_item_form.rhtml -->
  <h2>Add a new item to the <%= new_item_form.size %> already in this
  list</h2>
 
<%= form_tag :action => _new_ %>
  
Item: <%= text_field "product", "name" %>
  
<%= submit_tag "Add new item" %>
  <%= end_form_tag %>

See Also


1 2 3 4
Latest "Green" Packing Material? Mushrooms!

EcoCradle packaging material is composed of agricultural byproducts bound by fungal roots.

A new packing material that grows itself is now appearing in shipped products across the country.

The composite of inedible agricultural waste and mushroom roots is called Mycobond™, and its manufacture requires just one eighth the energy and one tenth the carbon dioxide of traditional foam packing material.

And unlike most foam substitutes, when no longer useful, it makes great compost in the garden.

The technology was the brainchild of two former Rensselaer ...

More at http://www.nsf.gov/news/news_summ.jsp?cntn_id=117385&WT.mc_id=USNSF_51&WT.mc_ev=click


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.