How to Use remote: true to Make Ajax Calls in Rails

codenode
5 min readJun 30, 2016

--

The Rails documentation for remote: true is great at explaining how to add the helper to your views. It does not, however, fully explain how remote: true works in tandem with a controller and a Javascript file to generate and manage JSON responses to the ajax call. AJAX involves a clientside (browser) request to your server that generates a response back to the client that must be handled.

Below is a short tutorial on how to craft the full circuit of requesting and responding via remote: true ajax calls in Rails.

The View: Making the ajax request with remote: true

<%= link_to “Add a Book”, books_path, class: "add", remote: true %>

You can add the Rails helper remote: true to any other Rails helper that generates a web request. The Rails docs provide several helpful examples of adding the helper to form_for, form_tag, link_to, and button_to.

Once added, the remote: true helper will stop the default action of the object (also known as preventDefault() in Javascript) and instead perform an asynchronous request to the appropriate controller action. You’ll need to make sure that you provide a path for the appropriate request type. In the above example I’ve used a POST request action to the books#create action in the BooksController by using its helper books_path.

With your path and remote: true set, a button will no longer click and refresh the page, it will just make an ajax call quietly. A form will no longer submit, it will just send form data without a refresh via an ajax call. Etc. In sum: All it takes to create the ajax request is adding remote: true to an object that can generate that request and ensuring its path goes to the correct controller action.

The Controller: Receiving the request and generating a response

Okay, so you’ve made your request and now you need to set your controller up to receive it. To check that the remote: true request is working, insert a debugger (pry, byebug, etc) into the top of your controller action and initiate the ajax call via the form or link object by clicking it in your browser. You should see your debugger pop open and confirm that the controller action was in fact hit. If the debugger doesn’t instantiate, check your routes.rb file to make sure that you’ve properly declared a route for that action. Common pairings are a form making a POST request to the create action of a controller or a delete button making a DELETE request to the destroy action of a controller.

Now that your remote: true request is confirmed working by the instantiation of your debugger in the controller action, you can proceed with manipulating the parameters received by the action. Check to see what’s included in your parameters by typing params into the console opened by your debugger. This will show you the exact JSON that your controller receives in the request.

Different requesting objects will generate different kinds of params. A form will have a familiar parameter hash of all of the form values plus some encasing information. A link may just have the controller and action stated without much else. In any of these cases, you may find yourself needing to pass additional information into the params along with your request. You can do this by adding them to the path helper (link, button) or with a hidden field (forms) like so:

<%= link_to “Add a Book”, books_path(book_id: book.id), class: "add", remote: true %>

The params will now include your supplied keys and values like so:

{"controller"=>"books", "action"=>"create", "book_id"=>"42"}

Now I’ll assume you know how to create, build, destroy or otherwise package your object with these params and that you’ve now stored it in an instance variable such as @book.

The next step is to render a JSON response back to the DOM element that made the ajax request. Your Rails controller can handle this just as it can handle rendering partials, redirecting to new routes, or any number of subsequent routing activities. The easiest way to do this is to simply render the object as JSON:

render json: @book 

This will supply the receiving object with attributes about the book object. However because you are passing back to a Javascript file that does not have access to your DB or to Rails helpers directly, you may want to supply a string of HTML that contains everything the JS file will need to insert a new book element into the DOM. Let’s say you would like to insert a partial that contains information about the book as well as about the user who added the book. Here’s an expanded JSON response you can construct:

render json: { book: render_to_string(‘books/_book’, layout: false, locals: { book: @book, @user}) }

The above instructs the controller’s create action to return a JSON object that contains information about a review. Specifically, it contains a stringified piece of HTML taken from a partial in your views that supplies information about two instance variables you provide as local variables to the partial. I like this approach because it allows you to construct the DOM elements from templates in your Rails ERB file views rather than maintaining them as floating bits of HTML in your JS files.

Javascript: Handling the response and manipulating the DOM

You’re almost done! You’ve now got a link generating a remote or asynchronous web request to your controller’s create action. That controller action is generating a JSON response that contains information about an object your controller prepared. All that’s left is to take this JSON response and use it to manipulate the DOM — in other words, to show your user what their click just did.

In your Javascript file, you’ll need to select the element that made the original request and set up an event to listen for the success of your ajax request on that element. This is super easy with jQuery and with the class that we added in to our link_to helper earlier in tutorial:

$(‘.add a’).on (‘ajax:success’, addBook)

This tells the browser to listen for an ajax success event (a successfully completed AJAX call returning a 200 status) on the link in class “add.” Once that success event happens, the addBook callback function should run.

All that’s left is to construct our addBook function using the JSON data that is passed into the callback:

function addBook(event, data) {  $(‘.book-list’).append(data.book)}

Here we’re receiving the event (event) and the JSON (data) back as parameters in our callback. Then we’re appending the book data from the JSON into the DOM in a conveniently named “book list” class. Here data.book contains the stringified book partial that has information about our book and the user for display.

Inserting another object is as simple as providing it back in the controller via JSON and referencing it here or inserting a manually constructed string of HTML from the Javascript file. You can also add classes, change button values, or do any number of other manipulations that give the user visual evidence that their click has resulted in and recorded a change in state.

Important: You can also supply a callback function to run if the ajax request generates an error response. The event to listen for would then be an error for which you define a separate callback. You might show a pop up or refresh the form field in this callback so that the user knows their action somehow failed:

$(‘.add a’).on (‘ajax:error’, displayError)

That’s it!

Now you have everything you need to do both the clientside and serverside work to handle ajax requests and responses in your Rails app. Have fun adding asynchronous behaviors and moving your application closer and closer to a single page experience (eliminating those pesky, latent web requests!). Your users will be much better for it.

--

--