Section 2.3. Bringing Rails into the Picture


2.3. Bringing Rails into the Picture

Rails provides convenient integration with Prototype, in the form of helper methods that generate Prototype calls. Next we'll discover how to do Ajax without writing any JavaScript, using the link_to_remote( ) helper method.

First, we need to back up a little and look at Rails' system for handing views.

2.3.1. ERb Basics

If you've ever used PHP, ColdFusion, ASP, JSP, or something similar, this will be a familiar concept. Embedded Ruby (ERb) lets you mix Ruby snippets into your HTML. ERb defines a set of special tags that get interpreted as Ruby; everything else is assumed to be plain HTML and is passed through untouched. Here are the special tags:

<%=  %>

The most common one, this holds a Ruby expressionwhich is output in place of the tag.
<%= -%>

Works just like the above but suppresses newline characters from the output after the tag, which allows for cleanly organized templates without extraneous whitespace in the HTML output.
<%   %>

This holds a piece of Ruby code but doesn't output anything.
<%  -%>

Works just like the above but suppresses newline characters after the tag.
<%#  %>

This is a Ruby comment, which is ignored and nothing is output.


Let's look at an example.

Remember our discussion of MVC in Chapter 1? Here is where it begins to come into play. Typically, a controller will receive a request for a page, and assemble the data needed for the view. In Rails, that data is put into instance variables (which are recognizable by the ugly @ sign that they all start with). So, imagine that we have this controller action:

def myaction   @foo = "Hello, world!" end

The action defines a variable called @foo, and puts the string Hello, world! into it. Our template could then contain this:

<%= @foo %>

And, when the template is accessed, <%= @foo %> would be replaced with Hello, world!. Pretty obvious stuff. In practice, you would usually want the variable to appear within some HTML structure, for example:

<h1><%= @foo %></h1>

Because the <% %> tag doesn't produce any output, its most common use is for control structures, such as if statements and each iterations. Unlike some other templating systems, there is no ERb-specific syntax for these constructs; it uses regular Ruby statements. A few examples:

<% if @page_title %><h1><%= @page_title %></h1><% end %> <% unless @names.empty? %>   <ul>     <% @names.each do |name| %><li><%= name %></li><% end %>   </ul> <% end %>

Take a look at the second line. It starts with the unless conditionalRuby shorthand for if not. Also take notice of @names.empty?. All Ruby arrays have a method called empty?by convention, Ruby methods that return true or false end with a question mark. The last thing to note is the fourth line. The each method on @names iterates over each member of the array so this code will walk through the @names array, and output an HTML list item for each name.

2.3.2. Layouts

Layouts are special templates that hold the markup common to multiple views. In other templating systems, this is often achieved by having headerandfooter templatefiles that get included in the page template. Rails does just the inverseyour headers and footers are defined in one layout file, and the body of the page is included from there. Layouts are stored in app/views/layouts, and by default Rails will first look for one with the name of the current controller, such as chapter2.rhtml. If that's not found, it will look for one called application.rhtml. The contents of your layout might look like this:

<html>   <head>     <title>My Rails Application</title>     <%= javascript_include_tag "prototype" %>   </head>   <body>     <%= yield %>   </body> </html>

The most important part to note is <%= yield %>. Think of it as yielding the code from the view template. In other words, it will insert the result of the view templates into the layout. Don't forget to include it in your layout, or your pages will appear blank.

2.3.3. Partials

Partials are subtemplates, designed for chunks of markup that you'll reuseor perhaps you just want to keep them in a separate file, to keep your templates tidy. Partials are easy to identify because their filenames always start with an underscore. For instance, you might create a file app/views/chapter2/_person.rhtml, containing the following:

<p><%= person.name %></p>

From your main template, you'd then include the partial like so:

<%= render :partial => "person" %>

There is a bit of magic involved in passing variables to the partial. Because the partial is named "person," the main template will look for an instance variable @person, and pass it to the partial as a local variable, person. What if the instance variable doesn't match the name of the partial? Then you'd explicitly pass it, like this:

<%= render :partial => "person", :locals => { :person => @scott } %>

All the key/value pairs in the :locals hash will be made into local variables for the partial.

A common application of partials is looping over an array of objects and rendering the partial for each one. The render method makes that easy with the :collection option. For example:

<%= render :partial => "person", :collection => @people %>

In this example, the main template has an array @people that will be looped through, passing a local variable person to the partial.

By default, partial templates are expected to be in the same directory as the main template. To render partials from other controllers, just include the directory name as a prefix. For example:

<%= render :partial => "chapter1/person" %>

Even though the main template might be chapter2/index.rhtml, the partial will be rendered from chapter1/_person.rhtml.

2.3.4. Helpers

Helpers are simply Ruby methods that are available in your templates, providing another way to keep your templates clean and readable. One helper file is created for each controller, so Chapter2Controller will have a corresponding file in app/helpers/chapter2_helper.rb. If you want a helper to be available across all controllers, define it in application_helper.rb.

Rails provides a number of built-in helpers that are used extensivelyin fact, we've already seen a few of them. In the "Layouts" section above, line four is a helper call:

<%= javascript_include_tag "prototype" %>

javascript_include_tag( ) is a Ruby method, defined by Rails, that takes a string argument (or an array of strings) and returns a piece of HTML like:

<script src="/books/4/386/1/html/2//javascripts/prototype.js" type="text/javascript"></script>

Another useful helper is h, which escapes HTML. For example, <%= h @foo %> will escape HTML characters in its output, which is an important security measure when redisplaying user input. We'll discuss the implications in-depth in Chapter 8.

Perhaps the most common helper you'll use is link_to, which simply generates a link element. For example:

<%= link_to "Click here", :url => "/chapter2/myresponse" %>

This helper outputs: <a href="/chapter2/myresponse">Click here</a>.

That's a pretty trivial example, but the interesting thing is that rather than taking a regular URL as a parameter, you can also give it a controller name, action name, and other parametersand the URL will be constructed for you. The power here is that when you redefine your routes, your links will automatically be changed to match.

<%= link_to "Click here", :action => "myresponse" %>

The output of this version is just the same as above. Notice we didn't specify the name of the controllerif it's left out, Rails assumes you want to use the same controller you're already in.

Internally, link_to uses another helper, url_for, to generate the link's URL. The url_for helper takes a hash of parameters and matches them against your application's routes to return a URL. Any keys that don't have a corresponding place in the route will be appended as query strings. In addition, there are a few hash keys that have special meaning:

  • :anchor is used to append an anchor (the portion of the URL after the # sign) onto the path.

  • :only_path can be true or false; if true, the protocol and host portion of the URL will be omitted.

  • :trailing_slash can be set to true to append a slash to the end of the URLwhich is usually not necessary and can conflict with page caching.

  • :host can be specified to override the current host.

  • :protocol, if given, overrides the current protocol (e.g., HTTP, HTTPS, FTP).

For example:

url_for :only_path => false, :protocol => 'gopher:// ',    :host => 'example.com', :controller => 'chapter2',    :action => 'myresponse', :trailing_slash => true, :foo => 'bar',    :anchor => 'baz' #=> 'gopher://example.com/chapter2/myresponse?foo=bar/#baz'

The idea of separating actual URLs from locations within the application (controller and action) is central to Rails; it's almost always preferable to point to a location in the application and let Rails generate the actual path according to the routing rules.

2.3.5. Back to Ajax

We've established the major concepts in Rails' view system, which is everything needed to get back to Ajax. In myaction.rhtml, add this (assuming you already included prototype.js earlier in the document):

<p><%= link_to_remote "Alert with Javascript Helper", :url =>    "/chapter2/myresponse", :success => "alert(request.responseText)" %></p>

This example uses the link_to_remote JavaScript Helper, which is the Ajax variant of the link_to helper explained earlier. If you view the source generated by the helper, you'll see this:

<p><a href="#" onclick="new Ajax.Request('/chapter2/myresponse',  {onSuccess:function(request){   alert(request.responseText) }}); return false;">Alert with Javascript Helper</a></p>

This code does the same thing as our first Ajax example: it makes a link with an onclick attribute that creates an XMLHttpRequest for /chapter2/myresponse and passes the result to alert( ). If we want to insert the text into the page rather than use alert( ), things get even simpler:

<p><%= link_to_remote "Update  with Javascript Helper", :url =>   {:action => "myresponse"}, :update => "response5" %></p> <p ></p>

Notice that instead of passing a :success option, we're passing an :update option, which is expected to be a DOM element ID. When :update is specified, the helper uses Prototype's Ajax.Updater instead of Ajax.Request. One other difference: in every other example so far, the request URL has been specified as an absolute path, /chapter2/myresponse. That works, but it's a bit confining (as discussed previously in the "Helpers" section). This time, we just specify the action name, and let the actual URL be generated. The code generated by the helper looks like this:

<p><a href="#" onclick="new Ajax.Updater('response5', '/chapter2/myresponse');  return false;">Update  with Javascript Helper</a></p> <p ></p>

We've hit quite a milestone here: for the first time, we have an Ajax call without writing any JavaScript at all.




Ajax on Rails
Ajax on Rails
ISBN: 0596527446
EAN: 2147483647
Year: 2006
Pages: 103
Authors: Scott Raymond

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