Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Agile Web Development With Rails, 1st Edition (2005).pdf
Скачиваний:
28
Добавлен:
17.08.2013
Размер:
7.99 Mб
Скачать

HELPERS 332

The strange sequence %3cb%3ethere%3c/b%3e is a URL-encoded version of the HTML <b>there</b>. Our template will substitute this in, and the page will be displayed with the word there in bold.

This might not seem like a big deal, but at best it leaves your pages open to defacement. At worst, as we’ll see in Chapter 21, Securing Your Rails Application, on page 427, it’s a gaping security hole that makes your site vulnerable to attack and data loss.

Fortunately, the solution is simple. Always escape any text that you substitute into templates that isn’t meant to be HTML. rhtml templates come with a method to do just that. Its long name is html_escape( ), but most people just call it h( ).

The value of name is <%= h(params[:name]) %>

Get into the habit of typing h( immediately after you type <%=.

You can’t use the h( ) method if you need to substitute HTML-formatted text into a tempate, as the HTML tags will be escaped: the user will see <em>hello</em> rather than hello. However, you shouldn’t just take HTML created by someone else and display it on your page. As we’ll see in Chapter 21, Securing Your Rails Application, on page 427, this makes your application vulnerable to a number of attacks.

The sanitize( ) method offers some protection. It takes a string containing HTML and cleans up dangerous elements: <form> and <script> tags are escaped, and on= attributes and links starting javascript: are removed.

The product descriptions in our Depot application were rendered as HTML (that is, they were not escaped using the h( ) method). This allowed us to embed formatting information in them. If we allowed people outside our organization to enter these descriptions, it would be prudent to use the sanitize( ) method to reduce the risk of our site being attacked successfully.

17.4 Helpers

Earlier we said that it’s OK to put code in templates. Now we’re going to modify that statement. It’s perfectly acceptable to put some code in templates—that’s what makes them dynamic. However, it’s poor style to put too much code in templates.

There are two main reasons for this. First, the more code you put in the view side of your application, the easier it is to let discipline slip and start adding application-level functionality to the template code. This is definitely poor form; you want to put application stuff in the controller

Prepared exclusively for Rida Al Barazi

Report erratum

HELPERS 333

David Says. . .

Where’s the Template Language?

Many environments have stigmatized the idea of code in the view—for good reasons. Not all programming languages lend themselves well to dealing with presentational logic in a succinct and effective way. To cope, these environments come up with an alternative language to be used instead of the primary when dealing with the view. PHP has Smarty, Java has Velocity, Python has Cheetah.

Rails doesn’t have anything because Ruby is already an incredibly wellsuited language for dealing with presentational logic. Do you need to show the capitalized body of a post, but truncating it to 30 characters? Here’s the view code in Ruby.

<%= truncate(@post.body.capitalize, 30) %>

On top of being a good fit for presentation logic, using Ruby in the view cuts down on the mental overhead of switching between the different layers in the application. It’s all Ruby—for configuration, for the models, for the controllers, and for the view.

and model layers so that it is available everywhere. This will pay off when you add new ways of viewing the application.

The other reason is that rhtml is basically HTML. When you edit it, you’re editing an HTML file. If you have the luxury of having professional designers create your layouts, they’ll want to work with HTML. Putting a bunch of Ruby code in there just makes it hard to work with.

Rails provides a nice compromise in the form of helpers. A helper is simply a module containing methods that assist a view. Helper methods are output-centric. They exist to generate HTML (or XML)—a helper extends the behavior of a template.

By default, each controller gets its own helper module. It won’t be surprising to learn that Rails makes certain assumptions to help link the helpers into the controller and its views. If a controller is named BlogController, it will automatically look for a helper module called BlogHelper in the file blog_helper.rb in the app/helpers directory. You don’t have to remember all these details—the generate controller script creates a stub helper module automatically.

Prepared exclusively for Rida Al Barazi

Report erratum

HELPERS 334

For example, the views for our store controller might set the title of generated pages from the instance variable @page_title (which presumably gets set by the controller). If @page_title isn’t set, the template uses the text “Pragmatic Store.” The top of each view template might look like

<h3><%= @page_title || "Pragmatic Store" %></h3>

<!-- ... -->

We’d like to remove the duplication between templates: if the default name of the store changes, we don’t want to edit each view. So let’s move the code that works out the page title into a helper method. As we’re in the store controller, we edit the file store_helper.rb in app/helpers.

module StoreHelper def page_title

@page_title || "Pragmatic Store" end

end

Now the view code simply calls the helper method.

<h3><%= page_title %></h3>

<!-- ... -->

(We might want to eliminate even more duplication by moving the rendering of the entire title into a separate partial template, shared by all the controller’s views, but we don’t talk about them until Section 17.9, Partial Page Templates, on page 359.)

Sharing Helpers

Sometimes a helper is just so good that you have to share it among all your controllers. Perhaps you have a spiffy date-formatting helper that you want to use in all of your controllers. You have two options.

First, you could add the helper method to the file application_helper.rb in app/helpers. As its name suggests, this helper is global to the entire application, and hence its methods are available to all views.

Alternatively, you can tell controllers to include additional helper modules using the helper declaration. For example, if our date formatting helper was in the file date_format_helper.rb in app/helpers, we could load it and mix it into a particular controller’s set of views using

class ParticularController < ApplicationController

helper :date_format

# ...

You can include an already-loaded class as a helper by giving its name to the helper declaration.

Prepared exclusively for Rida Al Barazi

Report erratum

FORMATTING HELPERS 335

class ParticularController < ApplicationController

helper DateFormat

# ...

You can add controller methods into the template using helper_method. Think hard before doing this—you risk mixing business and presentation logic. See the documentation for helper_method for details.

17.5 Formatting Helpers

Rails comes with a bunch of built-in helper methods, available to all views. In this section we’ll touch on the highlights, but you’ll probably want to look at the Action View RDoc for the specifics—there’s a lot of functionality in there.

One set of helper methods deals with the formatting of dates, numbers, and text.

<%= distance_of_time_in_words(Time.now, Time.local(2005, 12, 25)) %>

248 days

<%= distance_of_time_in_words(Time.now, Time.now + 33, false) %>

1 minute

<%= distance_of_time_in_words(Time.now, Time.now + 33, true) %> half a minute

<%= time_ago_in_words(Time.local(2004, 12, 25)) %>

116 days

<%= human_size(123_456) %>

120.6 KB

<%= number_to_currency(123.45) %> $123.45

<%= number_to_currency(234.56, :unit => "CAN$", :precision => 0) %>

CAN$235.

<%= number_to_percentage(66.66666) %>

66.667%

<%= number_to_percentage(66.66666, :precision => 1) %>

66.7%

<%= number_to_phone(2125551212) %>

212-555-1212

Prepared exclusively for Rida Al Barazi

Report erratum

FORMATTING HELPERS 336

<%= number_to_phone(2125551212, :area_code => true, :delimiter => " ") %>

(212) 555 1212

<%= number_with_delimiter(12345678) %>

12,345,678

<%= number_with_delimiter(12345678, delimiter = "_") %>

12_345_678

<%= number_with_precision(50.0/3) %>

16.667

<%= number_with_precision(50.0/3, 1) %>

16.7

The debug( ) method dumps out its parameter using YAML and escapes the result so it can be displayed in an HTML page. This can help when trying to look at the values in model objects or request parameters.

<%= debug(params) %>

--- !ruby/hash:HashWithIndifferentAccess name: Dave

language: Ruby action: objects controller: test

Yet another set of helpers deal with text. There are methods to truncate strings and highlight words in a string (useful to show search results, perhaps).

<%= simple_format(@trees) %>

Formats a string, honoring line and paragraph breaks. You could give it the plain text of the Joyce Kilmer poem Trees and it would add the HTML to format it as follows:

<p> I think that I shall never see <br />A poem lovely as a tree.</p>

<p>A tree whose hungry mouth is prest

<br />Against the sweet earth’s flowing breast; </p>

<%= excerpt(@trees, "lovely", 8) %>

...A poem lovely as a tre...

<%= highlight(@trees, "tree") %>

I think that I shall never see

A poem lovely as a <strong class="highlight">tree</strong>.

Prepared exclusively for Rida Al Barazi

Report erratum