Tutorial: How to debug AJAX in Rails
One of the most common issues I notice with less experienced programmers is that they don’t understand how to approach debugging AJAX in a Rails app. I will explain the approach that I personally use to debug ajax.
Client vs Server
As most programmers know, javascript is a client side programming language which means the code executes on the end user’s browser, and Ruby code is a server side programming language which means it gets executed on the server.
This concept can cause confusion because some programmers are not really sure how data gets from the client (javascript) to the server (ruby/rails).
Let’s break this down into a simple example.
Sending Data to the Server
Let’s say we have a scenario where we want to send a user’s name to the server and then save it to the database.
Here’s an example jQuery snippet where we’re sending a user’s name from the client to the server.
// Create a variable in JSON format
var user = {
first_name: 'Jeff',
last_name: 'Smith'
}
// Post data via ajax to a rails controller
$.post('/users', user);
If we break this down, this just creates a javascript variable called user
with the attributes first_name
and last_name
.
// Create a variable in JSON format
var user = {
first_name: 'Jeff',
last_name: 'Smith'
}
It’s a JSON object so you can get the first name by executing user.first_name
and the last name by user.last_name
.
This is where the magic of sending the data from the client to the server happens.
// Post data via ajax to a rails controller
$.post('/users', user);
If you look at the jQuery documentation https://api.jquery.com/jQuery.post/ for the $.post
method, you can see that the first parameter is the url where the data should be sent to, and the second parameter is the data itself.
In our code, we’re sending data to the /users
path of our rails app, and we’re passing in that user
variable that we created.
Getting the data on the server, that was sent from the client
Here’s a pretty typical create method of a controller. It simply creates a new User record in the database from the params passed in.
class UsersController < ApplicationController
def create
@user = User.new(params[:user])
respond_to do |format|
if @user
format.html { redirect_to @user, notice: 'User was successfully created.' }
else
format.html { render action: "new" }
end
end
end
end
Debugging
Ok so you let’s say you have both this javascript and ruby code in your project, but the user record is not getting created. You need to somehow step through the code line by line to see where the problem is occurring.
I’m going to start at the beginning of the process and show you how to step through the code using logging. Note that there are different ways of debugging, but this is the easiest because it does not require any external libraries.
The easiest way to debug in javascript is to use the developer tools in your browser. They are built in to many browsers, but my personal preference is using the Firebug plugin in Firefox.
Debugging the javascript
By putting this line in your code, when it gets executed, it will print I log to the browser’s console
in the browser’s console.
console.log(“I log to the browser’s console”);
If I modify our original javascript code with some logging statements and then execute the code, you can see that i’m logging the user’s name, and then also logging the user object to the console.
// Create a variable in JSON format
var user = {
first_name: 'Jeff',
last_name: 'Smith'
}
console.log("user's name = " + user.first_name + " " + user.last_name);
console.log(user);
// Post data via ajax to a rails controller
$.post('/users', user);
So we can see that the data exists as we would expect it. The next line we need to step through is the $.post
to the server.
Debugging the Ruby
There are a few ways to log in a rails app. The one that i’m going to cover is the default standard out which logs to the rails console.
If you execute the following in your rails code, it will log Logging to the rails console
in the rails console.
puts "Logging to the rails console"
In a POST request to a rails method, the params
variable contains the data that was passed in via the $.post
request in our javascript.
Here’s the modified create method that contains the puts
line.
class UsersController < ApplicationController
def create
puts “user = “
puts params[:user]
@user = User.new(params[:user])
respond_to do |format|
if @user
format.html { redirect_to @user, notice: 'User was successfully created.' }
else
format.html { render action: "new" }
end
end
end
end
If you run this code in your rails app and then look at the rails console, you will see the following output.
user =
{“first_name"=>"Jeff", “last_name”=>"Smith"}
You will also notice that on every request the parameters are automatically printed to the rails console and looks something like this.
Started POST "/users" for 127.0.0.1 at 2014-04-13 10:44:36 -0500
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", “authenticity_token"=>"2Ct5hb/I3+u87PGGw3nRpvMNUE7Enjfu1ZSwsQr6qMc=", “user"=>{"first_name"=>"Jeff", “last_name"=>"Smith"}, "button"=>""}
Since the user object in the params looks like this
user"=>{"first_name"=>"Jeff", “last_name”=>"Smith"}
If you wanted to log just the first or last name, you could do this.
puts params[:user][:first_name]
and it would print this to the rails console
Jeff
If I add more puts lines to the create method, I can narrow down the area that is causing my user object not to save to the database in this example.
Since we know the data is being correctly sent from the javascript to the create method, we can then debug further in our create method.
class UsersController < ApplicationController
def create
puts "user = "
puts params[:user]
@user = User.new(params[:user])
respond_to do |format|
if @user
format.html { redirect_to @user, notice: 'User was successfully created.' }
else
format.html { render action: "new" }
end
end
end
end
The next thing I would do is to add puts
statements inside our if/else statement so we can figure out if the code in the if
statement is being executed or if the code in the else
statement is being executed.
if @user
puts "We’re in the IF statement"
format.html { redirect_to @user, notice: 'User was successfully created.' }
else
puts "We’re in the ELSE statement"
format.html { render action: "new" }
end
If i run my code now, the following is getting output in the rails console
user =
{“first_name"=>"Jeff", “last_name”=>”Smith"}
We’re in the IF statement
Ok so now that I know we’re actually getting inside the IF statement, which we know is where the code should be getting into if the record is being saved, we know that we need to check why are we getting into the if statement and the record is not saving to the database.
In this example, our if statement is
if @user
That basically translates to “If the @user object exists”. So yes the @user
object exists because we created with the following line and if I were to add another puts
statement after we create @user
, I would see that it exists.
@user = User.new(params[:user])
So now I know that in the create method, the code is following the path that I would expect. But wait a minute I don’t recall actually saving the @user
object anyways.
Ah ha! This line
if @user
should actually be
if @user.save
Now if we run this code we can see that it actually saves the record to the database.
Conclusion
Now this is a very simple example, but it demonstrates some very important principles when it comes to debugging AJAX in a rails application.
Just remember to always step through your code to make sure data and variables are what you expect them to be.