#58

6
Dynamically Generate a Selection List in a Rails Template #58 Chapter 7, Work with Ajax and Ruby on Rails | 299 HACK Chapters 6 and 8, respectively, for discussions of the Prototype and script. aculo.us libraries). As a result, the JavaScript in application.js is available for code in the template to call. For example, monitor.rhtml includes this code: <div id="complete" style= "font-size: 1.2em; color: green" onclick="clearIt($('complete'))"></div> clearIt() is defined in application.js. It sets the innerHTML property of the element referenced by its parameter to the empty string "": function clearIt(elId){ if(elId != null){ elId.innerHTML=""; } } Using javascript_include_tag() involves a single step for importing application.js and any other necessary packages (such as Prototype), but you are certainly free to place your own JavaScript file in the javascripts direc- tory and then include a script tag to import it in the Rails template: <script src="/javascripts/myfunctions.js" type="text/javascript"></script> You can use javascript_include_tag() with different parameters to import individual JavaScript files, as in these two examples: javascript_include_tag "/javascripts/myfunctions.js","/scripts/morefuncs.js" #As long as the scripts directory is located in #the Rails <web-app-root>/public directory HACK #58 Dynamically Generate a Selection List in a Rails Template Hack #58 Generate a selection list from server-side data using Ajax and Ruby on Rails. This hack creates a select element from server-side data using a Ruby on Rails application. Unlike the typical manner in which a web widget is gener- ated in a web page, the user chooses the content for the pop-up, and then the pop-up appears out of the blue, without anything else on the page changing. The selections that the user sees in the pop-up derive from a server-side component; they are not just hard-coded JavaScript or HTML that is part of the web page. This hack has the same behavior as some of our earlier hacks, but the path our code takes to produce its effects is quite different. A Rails application wraps all of the XMLHttpRequest mechanics behind its own methods. Figure 7-9 shows what the web page looks like. The user reaches this page by typing http://localhost:3000/hacks/ into a web browser’s location field. ,ch07.4450 Page 299 Wednesday, March 8, 2006 12:01 PM

Upload: sampetruda

Post on 14-Jun-2015

256 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: #58

Dynamically Generate a Selection List in a Rails Template #58

Chapter 7, Work with Ajax and Ruby on Rails | 299

HACK

Chapters 6 and 8, respectively, for discussions of the Prototype and script.aculo.us libraries). As a result, the JavaScript in application.js is available forcode in the template to call. For example, monitor.rhtml includes this code:

<div id="complete" style="font-size: 1.2em; color: green" onclick="clearIt($('complete'))"></div>

clearIt( ) is defined in application.js. It sets the innerHTML property of theelement referenced by its parameter to the empty string "":

function clearIt(elId){ if(elId != null){ elId.innerHTML=""; }}

Using javascript_include_tag( ) involves a single step for importingapplication.js and any other necessary packages (such as Prototype), but youare certainly free to place your own JavaScript file in the javascripts direc-tory and then include a script tag to import it in the Rails template:

<script src="/javascripts/myfunctions.js" type="text/javascript"></script>

You can use javascript_include_tag( ) with different parameters to importindividual JavaScript files, as in these two examples:

javascript_include_tag "/javascripts/myfunctions.js","/scripts/morefuncs.js"#As long as the scripts directory is located in#the Rails <web-app-root>/public directory

H A C K

#58Dynamically Generate a Selection List in a RailsTemplate Hack #58

Generate a selection list from server-side data using Ajax and Ruby on Rails.

This hack creates a select element from server-side data using a Ruby onRails application. Unlike the typical manner in which a web widget is gener-ated in a web page, the user chooses the content for the pop-up, and thenthe pop-up appears out of the blue, without anything else on the pagechanging. The selections that the user sees in the pop-up derive from aserver-side component; they are not just hard-coded JavaScript or HTMLthat is part of the web page.

This hack has the same behavior as some of our earlier hacks, but the pathour code takes to produce its effects is quite different. A Rails applicationwraps all of the XMLHttpRequest mechanics behind its own methods.Figure 7-9 shows what the web page looks like. The user reaches this pageby typing http://localhost:3000/hacks/ into a web browser’s location field.

,ch07.4450 Page 299 Wednesday, March 8, 2006 12:01 PM

Page 2: #58

300 | Chapter 7, Work with Ajax and Ruby on Rails

#58 Dynamically Generate a Selection List in a Rails TemplateHACK

We’re using the WEBrick server that comes with Ruby onRails.

The user chooses either Team or Individual from the pop-up and clicks theShow Sports button, and another select list (whose values are determinedby the user’s choice in the first list) appears just above the button.

In a Rails application, a controller component takes charge of the views thatthe web user sees. The controller component is located inside the <web-app-root>/app/controllers directory. Using http://localhost:3000/hacks/ as anexample, the framework looks in <web-app-root>/app/controllers/hacks_controller.rb for an action or method named index that generates theresponse. Actions start out as Ruby methods within a controller object (aclass, in object-oriented terms) defined in this file.

The entire path on my Mac OS X machine is ~/Rails/Energy/app/controllers/hacks_controller.rb. Energy is the top-leveldirectory of the web application.

Let’s take a look at hacks_controller.rb for the index( ) method:

class HacksController < ApplicationController def index end#rest of class definition...end

Nothing happening there; it’s an empty method definition. In this case, Railslooks for a template named index.rhtml in the app/views/hacks directory.

Figure 7-9. Cop your own pop-up

,ch07.4450 Page 300 Wednesday, March 8, 2006 12:01 PM

Page 3: #58

Dynamically Generate a Selection List in a Rails Template #58

Chapter 7, Work with Ajax and Ruby on Rails | 301

HACK

One of the intuitive aspects of the Rails framework is thatthe framework maps URL path information, such as thehacks part of http://localhost:3000/hacks, to directories of thesame name in sensible locations, such as views.

index.rhtml provides the template for our hack:

<html><head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <%= javascript_include_tag :defaults %> <title>Ajax Rails &amp; Select lists</title></head><body><%= form_remote_tag(:update => "sel_con",:url => { :action => :create_select},:position => "top",:success => "$('sel_con').innerHTML=''" ) %><p>Please select a sports category:</p><p><%= select_tag "categories","<option>Team</option><option>Individual</option>" %></p><div id="sel_con"></div><p><%= submit_tag "Show Sports" %></p><%= end_form_tag %></body></html>

This template calls the form_remote_tag( ) method to update the div posi-tioned beneath the form tag. This method wraps all of the Ajax- and requestobject–related functionality, updating the div with server data and position-ing any more information on top of or before any existing div content (asspecified by the :position => "top" parameter). In other words, when theuser clicks the Show Sports button, an XMLHttpRequest object is created, andits send( ) method sends a request to a Rails action named create_select.This action is defined as a Ruby method in the hacks_controller.rb file wepeeked at before.

The create_select action renders the HTTP response, which specifies thetags and content of a new pop-up or select list. Figure 7-10 shows the resultof clicking the Show Sports button.

,ch07.4450 Page 301 Wednesday, March 8, 2006 12:01 PM

Page 4: #58

302 | Chapter 7, Work with Ajax and Ruby on Rails

#58 Dynamically Generate a Selection List in a Rails TemplateHACK

How is that response rendered, anyway? Let’s look at that part of the con-troller object:

class HacksController < ApplicationController def index end

def create_select

indArr=["Nordic Skiing", "Inline Skating","Tennis", "Triathlon","Road Racing","Figure Skating","Weight Lifting", "Speed Skating","Snowboarding"]; teamArr=["Soccer","Basketball","Football","Hockey", "Baseball","Lacrosse"]; str="";

if params[:categories].index('Team') != nil render :partial => "options", :locals => { :sports => teamArr,:sptype => "team"} elsif params[:categories].index('Individual') != nil render :partial => "options", :locals => { :sports => indArr, :sptype => "individual" } else str="<select id='individual' name='individual'> <option>unknown</option></select>"; render :text => str; end

#end method end #end class definitionend

Figure 7-10. Voilà, up pops a select list

,ch07.4450 Page 302 Wednesday, March 8, 2006 12:01 PM

Page 5: #58

Dynamically Generate a Selection List in a Rails Template #58

Chapter 7, Work with Ajax and Ruby on Rails | 303

HACK

This controller object stores two Ruby arrays in the variables indArr andteamArr (these values could alternatively be generated from a database).Remember the web page’s existing select list that gives the user a choice ofTeam or Individual? This is a select element with the name categories. Thebrowser submits this value as a form parameter to the Rails action. The codeuses the syntax params[:categories] to get this parameter’s value. Thenthings get interesting, in a Rails kind of way. The server still has to providean HTTP response to the Ajax request object.

The action uses the RoR render( ) method to send the HTML for a selectlist back to our application, with the array values as the select list contents:

render :partial => "options",:locals => { :sports => teamArr,:sptype => "team"}

render() specifies in its first parameter a partial named options. In Railslingo, a partial is just a template that contains a chunk of content that can beused over and over again—for example, one or a few HTML tags. Using theRails naming convention, the partial (really a text file) is placed in the app/views/hacks directory with its name preceded by an underscore, as in _options.rhtml. So, in plain English, the method call declares, “Render the response asthe _options partial content, and hand the partial two local variables, :sportsand :sptype.”

Don’t forget the : before the variable names!

A Little Partial PizzazzThe partial needs the array values to build the select list; these are storedin the teamArr variable. Rails uses its built-in naming convention forpartials (the underscore requirement) to find the correct content and ren-der it as the response. Let’s look at the partial _options.rhtml file:

<select id="<%= sptype %>" name="<%= sptype %>"><% sports.each do |sport| %><option><%= sport %></option><% end %></select>

A little embedded Ruby code gives the select element its id and name. Theembedded code then iterates through the array (passed into the partial bythe render( ) method) and creates an option element for each array mem-ber, as in <option>hockey</option>. Although a little server-side Ruby codewas involved, the code did not have to touch the request object or deal withfetching or massaging the return value.

,ch07.4450 Page 303 Wednesday, March 8, 2006 12:01 PM

Page 6: #58

304 | Chapter 7, Work with Ajax and Ruby on Rails

#58 Find Out Whether Ajax Is Calling in the RequestHACK

Cleanup CodeThe only bit of trickery involved is making sure that the application does notappend one new select list after another inside the div as the user clicks thebutton. We want all the existing selects in that div to be replaced by anynew ones. Therefore, we include a little cleanup code that empties the divbefore it’s updated with a new select list:

<%= form_remote_tag(:update => "sel_con",:url => { :action => :create_select},:position => "top",success => "$('sel_con').innerHTML=''" ) %>

success sequentially precedes the complete stage, so this code sets the div’scontent to the empty string before the new select list appears.

To handle any request failures, such as a downed web server,add this code from a prior hack as a form_remote_tag( )parameter:

#$('failure') is Prototype's shortcut for#document.getElementById('failure'):failure => "$('failure').innerHTML='Failure;request status='+request.status"

,ch07.4450 Page 304 Wednesday, March 8, 2006 12:01 PM