Recipe 5.9. Reusing Page Elements with Partials


Problem

You want to eliminate duplicate code in your templates by breaking off parts of the templates into smaller subtemplates. You would like to use these subtemplates multiple times in the same template, or even in different templates. For even more utility, these reusable templates should accept local variable passed to them as parameters.

Solution

Reuse template code by creating and rendering partials (subtemplates), optionally passing in variables from the parent template for use within these partials. To demonstrate this, set up a Properties controller with a list action that populates an instance variable with properties.

app/controllers/properties_controller.rb:

class PropertiesController < ApplicationController   def list     @properties = Property.find(:all, :order => 'date_listed',                                        :limit => 3)   end end

A partial is just like any other template, except that its filename begins with an underscore. Create a partial named _property.rhtml and in it, iterate over the contents of the @properties array, displaying its contents. Use the cycle method to alternate the row colors of property listings between white and the value of the local variable, bgcolor.

app/views/properties/_property.rhtml:

<div style="background: <%= cycle(bgcolor,'#fff') %>; padding: 4px;">   <strong>Address: </strong>   <%= property.address %><br />   <strong>Price: </strong>   <%= number_to_currency(property.price) %><br />   <strong>Description: </strong>   <%= truncate(property.description, 60) %> </div>

Render the _property.rhtml partial from the list.rhtml view by calling render, passing the name of the partial (its filename, without the underscore and file extension) to the :partial option. Additionally, pass in bgcolor as a local variable to the template by assigning it to the value of :bgcolor in a hash passed to the :locals option.

app/views/properties/list.rhtml:

<h3>Property Listings:</h3> <%= render(:partial => 'property',       :locals => {:bgcolor => "#ccc"},       :collection => @properties ) %>

Discussion

Calling the list action of the solution's Properties controller displays information about each property, displayed with alternating background colors. By default, partials have access to an instance variable with the same name as the partial, just as the list.rhtml partial has access to the @properties instance variable. If this default is not desirable, you can pass in whatever local variable you want by including it in a hash passed to the :locals option of render.

This partial could be called from any other template in your application by passing in an absolute path to the :partial option of render. In fact, if your partial contains any slashes at all, Rails will look for that partial relative to your application's app/view directory.

The solution passes :partial => 'property' to render, telling it to find the file named _property.rhtml in app/views/properties (the same directory as list.rhtml). If you had prefixed properties with a slash, such as :partial => '/property', then render would look for the same partial in app/views. This behavior is useful if you plan to share partials across the view templates of different controllers. A common convention is to create a directory in app/views for shared partials and then to prefix shared partial paths with a slash and the name of the shared directory (e.g., :partial => '/shared/property').

By creating the partial to handle the display of a single object, you get instant reuse. The same partial you called earlier from the list.rhtml template can now be used from the show.rthml template, which, by convention, renders a single model. Here's what the show template looks like:

app/views/properties/show.rhtml:

<h3>Property Listing: </h3> <%= render :partial => 'property',  :locals => {:property => @property} %>

Now add a show method to the controller:

app/controllers/properties_controller.rb:

class PropertiesController < ApplicationController   def list     @properties = Property.find(:all, :order => 'date_listed',                                        :limit => 3)   end   def show     @property = Property.find(params[:id])   end end

Figure 5-6 shows the results of each version of displaying multiple Property objects using partials.

Figure 5-6. A view showing a list of properties and a single property, both generated with the same partial


See Also

  • Section 5.5"




Rails Cookbook
Rails Cookbook (Cookbooks (OReilly))
ISBN: 0596527314
EAN: 2147483647
Year: 2007
Pages: 250
Authors: Rob Orsini

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net