IF you are looking for good tips on how to make proper AJAX calls in Ruby on Rails, this post is for YOU! I had to look around for the longest time to find good RoR examples of using AJAX, and yet, there really wasn’t a lot out there. However, once I finally figured out I realized how EASY Ruby on Rails makes using Javascript and AJAX calls. So now, I have come here to show YOU what took me soo long to figure out.
First off lets jump to our end goal. What are we trying to achieve? Let’s say we are creating an application and on one of our pages we want to gather information from our database without having to make the user redirect to another page or refresh the current one. This is exactly what AJAX was built for. Asynchronous calls between the server and the database.
In this example, we are going to implement a “building” search bar that will search our database for Building objects by building name. I have found this useful if you are trying to use google maps API and create a map with your own database stored buildings.
First things first… newer versions of Ruby on Rails such as 2.0 and above already have an awesome Javascript/AJAX library included: Prototype! This library is going to make our lives a LOT easier, however, I will also show you how to do these AJAX calls WITHOUT using Prototype so you see REALLY whats going on.
Open up your layout/application.html.erb or site.html.erb (yours could be named otherwise, but basically whatever layout you are using). Mine looks something like this:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title><%= @title %></title> </head> <body> <div id="container"> <div id="site_content"> <%= yield %> </div> </div> </body> </html>
We need to first allow our application to use the Prototype library by adding this to our <head> section:
<head> <title><%= @title %></title> <%= javascript_include_tag :defaults %> </head>
This will allow us to use all of the Prototype library calls. Next we need to create our Javascript function that will be called when the user hits our search button. (note: We could also use Prototype to have an AJAX called be sent on a time interval without having the user to click anything. This is similar to what facebook uses for notifying users of new notifications and messages.) I am going to call my function ajaxSearch(). You are going to also want to put your script in the layout header as well, so it is accessible on all pages.
<head>
<title><%= @title %></title>
<%= javascript_include_tag :defaults %>
<script>
function ajaxSearch() {
//this is where our search code will go
}; // end ajaxSearch function
</script> // end script
</head>
Now lets make our search bar and button so that we can call our ajaxSearch function, even though it is not filled with code yet. This code can be placed anywhere on the app. If you want it on every page you need to put it in the layout page, but if you want it on a single page, just put it on that one. Either decision you choose your code is going to look like something like this.
<div id="search_box"> <form action="#" onsubmit="ajaxSearch(); return false;"> // this sets ajaxSearch() to be called form submit <input style="width: 300px;" type="text" name="q" value="" id="q" /> <input id="search" type="submit" value="Search" /> </form> </div>
Okay. So now we have a text bar that we can write into and calls the ajaxSearch() function. Now we need to handle the call and do our AJAX search. Change your ajaxSearch to look like this.
function ajaxSearch() {
var query = document.getElementById('q').value;
if( query == '' ) { return; }
document.getElementById("search").value = 'Searching...';
document.getElementById("search").disabled = true;
// AJAX call will go here
}; // end ajaxSearch function
What we have done is saved the text in the box to query, returning if it is null, and changed our search bar to be unaccessible while the AJAX search will be working. Next we need to create our AJAX request. This is where Prototype is going to become our best buddy! Usually when you make a AJAX XMLHttpRequest you need to check for browser compatibility and do lots of other LONG code-y stuff that is good to know but quite annoying. Prototype library AJAX request handles all of this for you behind the scenes, and it comes with Rails! Now lets enter our AJAX request where the // AJAX call will go here – was:
req = new Ajax.Request('/buildings/ajax_buildings', {
method: 'get',
parameters: { q: query },
onComplete: function(transport) {
processReqChange(transport);
}
});
beautiful, isn’t it? What this does is sends an AJAX request to our Buildings controller and calls the ‘ajax_buildings’ action as a GET-er, while also sending the parameters params[:q], which is our query object, and on request completion will run processReqChange(), another function we must write. Lets take a look at our controller code, which in this example is for returning and array of Building objects. This part looks really sweet too.
// buildings/ajax_buildings <-- in buildings_controller.rb def ajax_buildings if params[:q] @buildings = Building.find( :all, :conditions => [ 'name LIKE ?', '%' + params[:q].downcase + '%'], :limit => 20) render :json => @buildings end end
This action searches our application database for all Building objects that have their name property containing the suggested word entered in the search bar – params[:q], and I just threw a limit of 20 on their to stop possible over-flooding of objects. We then return a rendered text, an array of buildings, in a json format. That is JavaScript Object Notation. Although JavaScript can not directly use this string, we can change it into its proper format in a second.
Now for the final piece of our puzzle, we need to create our processReqChange() function that is called once the AJAX search is finished.
// inside of our <script>
function processReqChange(req) {
// request is complete
if (req.readyState == 4) {
var results = req.responseText;
var buildings = eval("("+results+")");
var size = buildings.length;
if(buildings.length == 0) {
alert("No matches were found!");
return;
}
// do all the work you want with your data
// CODE
// CODE
// CODE
} // end if req == 4
}; // end function
Notice that what we sent in as ‘transport’ is now called ‘req’. First we double check to make sure the readyState is equal to 4, which means the AJAX request is completely finished and we may now do our work with the data. We then store the response text into ‘results’ (this is our array of buildings string in json format). The next line of code: var buildings = eval(“(“+results+”)”); – is a special command that I was told by my mentor is usually never used except for special circumstances, such as this! This essentially turns that string of a bulding array into an ACTUAL array that we can use! That’s right, we can USE it nowlike ANY other JavaScript array. buildings[0] will yield the first building in the array and you can use call ALL of the parameters of the building as such. Ex: buildings[0].name – will yield the first building’s name in the array.
Now that you have an array of the data you wanted, you can fill in the rest by manipulating and using that data however you want to. AWESOME! So, in conclusion, what we have done is easily and code-efficiently created a search bar that could potentially search and return any information, array of data or object from our database without having the user load or refresh to another page! It’s THAT easy!
Below is what your html.erb (or .rhtml) file would look liek put all together…
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title><%= @title %></title>
<%= javascript_include_tag :defaults %>
<script>
function ajaxSearch() {
var query = document.getElementById('q').value;
if( query == '' ) { return; }
document.getElementById("search").value = 'Searching...';
document.getElementById("search").disabled = true;
req = new Ajax.Request('/buildings/ajax_buildings', {
method: 'get',
parameters: { q: query },
onComplete: function(transport) {
processReqChange(transport);
}
}); // end ajax req
}; // end ajaxSearch function
function processReqChange(req) {
// request is complete
if (req.readyState == 4) {
var results = req.responseText;
var buildings = eval("("+results+")");
var size = buildings.length;
if(buildings.length == 0) {
alert("No matches were found!");
return;
}
// do all the work you want with your data
// CODE
// CODE
// CODE
} // end if req == 4
}; // end function
</script>
</head>
<body>
<div id="container">
<div id="site_content">
<div id="search_box">
<form action="#" onsubmit="ajaxSearch(); return false;"> // this sets ajaxSearch() to be called form submit
<input style="width: 300px;" type="text" name="q" value="" id="q" />
<input id="search" type="submit" value="Search" />
</form>
</div>
</div>
</div>
</body>
</html>
That, and putting in the correct Controller Action – ajax_buildings (or w/e your desired object is) and your set! This can be used for a lot of different things, such as calling objects, having a text search engine for your own site, uploading notifications instantly, basically anything you can imagine. It’s good to know that something as difficult as AJAX calls and JS functions can be so simple and straight forward! Thank you so much for reading my article on AJAX on Ruby on Rails. If you like it please feel free to leave a comment. You can also e-mail me if you have any questions at jbryant@inigral.com.
More information on the Prototype library can be found at their website: http://www.prototypejs.org/learn
If you liked this article, please link it on yours or any other site! Thanks a bunch guys! Good coding to all!
Posted by justinbgood