Section 2.1. The Old-Fashioned Way

2.1. The Old-Fashioned Way

To start off, let's do Ajax with the simplest thing that could possibly work: click a link and present a response from the serverusing XMLHttpRequest directly, without Prototype or Rails' JavaScript helpers.

Using XMLHttpRequest is often portrayed as being rocket science. But you'll find that, with a little practice and perhaps a couple new concepts, it's not as tricky as its reputation suggests.

2.1.1. Starting a Project

If you didn't create the example Rails skeleton in the last section, do so now, from your system's command line:

rails ajaxonrails cd ajaxonrails script/server

Browse to http://localhost:3000, and you should see Rails' welcome screen (for development purposes, script/server starts an HTTP server on port 3000). Back at the command line, let's generate a new controller called Chapter2Controller with an action called myaction. (Since you're already running the server in one terminal window, you'll want to open another.)

script/generate controller chapter2 myaction

The Rails generator is used to add on to the skeletonusually by generating new controllers and models. Of course, you could simply create a new controller file by hand, but using the generator saves typingwhich prevents typos.

The generator has another side effect: every time you generate a controller, a corresponding functional test file is generated as well. It's Rails' way of reminding you that testing is an important part of application development. To learn more about the available generators and their options, run script/generate without arguments.

Go to http://localhost:3000/chapter2/myaction. You should see the newly generated view as in Figure 2-1.

Figure 2-1. Newly generated Rails controller and view

Notice that, by default, the first part of the URL determines the controller, and the second part determines the actionthe method within the controller. Now edit the template for that action, which is in app/views/chapter2/myaction.rhtml. Add this bit of HTML to the bottom:

<p><a href="#" onclick="alert('Hello !');">Inline alert(  )</a></p>

As you can see, we're creating a paragraph with a basic linkbut instead of the usual HRef attribute, we use onclick, where we provide a JavaScript snippet to be run. Refresh your browser, and click the link. You'll see something like Figure 2-2.

Figure 2-2. Basic alert box

Having more than one or two statements inline in an onclick attribute would quickly get cumbersome. Let's extract it to a new JavaScript function, by adding this below everything else:

<p><a href="#" onclick="customAlert(  );">Call custom function</a></p> <script type="text/javascript">   function customAlert(  ) {     alert('Hello from a custom function.');   } </script>

Try it again, and see what happens. The result should be essentially the same as before.

Enough warm-up, let's do some Ajax. (But keep in mind, we are still peering under the hoodby the end of the chapter, the framework will hide much of the complexity.) First, you'll need to define a new action in the controller, app/controllers/chapter2_controller.rb. There's already an action called myaction, so let's call the new one myresponse. To create it, create a new file, myresponse.rhtml, inside app/views/chapter2. For the contents of the file, enter:

Hello from the server.

Just to make sure everything's working, try visiting that action in your browser at http://localhost:3000/chapter2/myresponse, and you'll see something like Figure 2-3.

Figure 2-3. Result of myresponse action

Now, back in myaction.rhtml, add another bit of HTML and JavaScript.

<p><a href="#" onclick="serverSideAlert(  );">Call server-side function</a></p> <script type="text/javascript">   function serverSideAlert(  ) {     var request = new XMLHttpRequest(  );'get', '/chapter2/myresponse', false);     request.send(null);     alert(request.responseText);   } </script>

Point your browser back to http://localhost:3000/chapter2/myaction, and click the new link. If all goes well, you'll get a message from the server, as seen in Figure 2-4. Be warned, this example won't work in Internet Explorer browsers prior to version 7 (we'll address that problem next).

Figure 2-4. Result of first Ajax call

Now we're getting somewhere! Just to convince yourself, take a look at the terminal prompt, where script/server is running. Every time you click the Ajaxified link, a new hit will register:

Processing Chapter2Controller#myresponse [GET]   Parameters: {"action"=>"myresponse", "controller"=>"chapter2"} Completed in 0.00360 (278 reqs/sec) | Rendering: 0.00027 (7%) |    200 OK [http://localhost/chapter2/myresponse]

The big problem with the current example is that it doesn't work in one of the most popular browsers, Internet Explorer 6. The reason is that Microsoft's implementation of XMLHttpRequest is an ActiveX object (actually, two of them, depending on the version of IE), which must be created differently. In order to cover all the bases, we'll need to create a little function to help sort it out. Here's the IE-safe version to add:

<p><a href="#" onclick="IEAlert(  );">Call server(IE-safe)</a></p> <script type="text/javascript">   function IEAlert(  ) {     function getRequestObject(  ) {       try { return new XMLHttpRequest(  ) } catch (e) {}       try { return new ActiveXObject("Msxml2.XMLHTTP") } catch (e) {}       try { return new ActiveXObject("Microsoft.XMLHTTP") } catch (e) {}       return false     }     var request = getRequestObject(  );'get', '/chapter2/myresponse', false);     request.send(null);     alert(request.responseText);   } </script>

This iteration is the same as before, except that instead of creating an XMLHttpRequest object directly, it calls getRequestObject( ), which walks through the possible options. The function makes use of TRy, a JavaScript statement that can be used to catch exceptions and stop them from bubbling up. (This example also introduces an idea that may be new to some developers, defining a function within a function.)

So far, we've been cheating a little, because the Ajax call isn't asynchronous. The third parameter of the ) method determines whether the call is asynchronous, and we have been setting it to false. Hence, request.send( ) is blockingthe JavaScript interpreter stops execution at that line and doesn't move on until the request comes back. To make the call asynchronous, we'll have to rearrange things some more. Add this block to myaction.rhtml:

<p><a href="#" onclick="asyncAlert(  )">Call async server-side</a></p> <script type="text/javascript">   function asyncAlert(  ) {     function getRequestObject(  ) {       try { return new XMLHttpRequest(  ) } catch (e) {}       try { return new ActiveXObject("Msxml2.XMLHTTP") } catch (e) {}       try { return new ActiveXObject("Microsoft.XMLHTTP") } catch (e) {}       return false     }     var request = getRequestObject(  );'get', '/chapter2/myresponse');     request.onreadystatechange = function(  ) {       if(request.readyState==4) alert(request.responseText);     }     request.send(  );   } </script>

In all the previous examples, we called request.send( ) and then immediately accessed request.responseText( ). Now that we're sending an asynchronous request, that's not possiblethe response might not have returned by the time it's referenced. To handle this problem, the XMLHttpRequest object has a readyState attribute that changes during the life cycle of a request. It also has an attribute called onreadystatechange, where you can define a function that will be called every time readyState changes. In this example, we define a function that checks to see if readyState is 4 (which means the request is complete; readyState codes are fully described in Chapter 3), and if so, presents an alert box. Dealing with asynchronous events can take some getting used to, but it's an essential part of programming Ajax by hand.

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

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: