Codementor Events

Tutorial: How to debug AJAX in Rails

Published Apr 14, 2014Last updated Mar 25, 2019

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”);

Console.log - Debug Ajax in Rails

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);

Console.log object

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.

Discover and read more posts from Tom Caflisch
get started
post commentsBe the first to share your opinion
Show more replies