Using AJAX in a Ruby on Rails App

AJAX is an important part of many Rails applications. It allows for making client-side changes without the need to reload the page. In this tutorial, you’ll see a very simple example of how to send a JavaScript response from the server and some of the more interesting things that can be done.

For this tutorial, we’ll be using AJAX to toggle between showing and hiding a menu of download options, which prevents them from cluttering up your screen when they aren’t needed. To get the code on GitHub, click here.

AJAX Demo V4.5

First, let’s outline what the mini app should do.

  • The home page needs to have a Show Options button which when clicked to reveal the download options.
  • With the download options revealed we should see:
    • Options for downloading data, a sample, or a demo.
    • A button to hide the download options.
  • Clicking the Hide Options button should return things back to how they were.

Adding the Controller

We’ll start by creating the controller at app/contollers/demo_controller.rb. For this tutorial, the show_options section is left empty. However, it can be used just like HTML views in terms of server-side logic. We use respond_to :html, :js to allow the server to provide a JavaScript response. This requires using the Responders gem, which we’ll add in the next step.

class DemoController < ApplicationController
  respond_to :html, :js

  def home
  end

  def show_options
  end

  def hide_options
  end

  def download
    if params[:data]
      send_data render_to_string(partial: 'demo/download/data'),
                type: 'text/plain; charset=UTF-8;',
                filename: "Data #{Time.current.to_formatted_s(:db)}.txt"
    elsif params[:sample]
      send_data render_to_string(partial: 'demo/download/sample'),
                type: 'text/plain; charset=UTF-8;',
                filename: "Sample #{Time.current.to_formatted_s(:db)}.txt"
    elsif params[:demo]
      send_data render_to_string(partial: 'demo/download/demo'),
                type: 'text/plain; charset=UTF-8;',
                filename: "Demo #{Time.current.to_formatted_s(:db)}.txt"
    end
  end
end

In the above code, we used predefined parameters to determine which file to download. This works well for a small number of downloads, around ten or less.  For a greater number of downloads, we should use a single param, such as params[:filename] to define what file should be downloaded. However, we would want to take greater care to ensure that the user cannot download an arbitrary file, for that would pose a security risk for the application. See the official Rails Security Guide for basic guidance on how to secure your application against arbitrary downloads. The general idea is to expand the download path and ensure that it’s where it is expected to be.

Update the Gemfile

Here, we just need to add gem 'responders' to the gemfile. Run bundle install in the terminal to finish the update. It’s likely that your app will need additional gems beyond this depedending on what your app will do.

Adding the routes

The routes are located in the config/routes.rb file. We add the routes required for the app to work. Routes map input urls to controller actions, so in this case one route is added for each action in the controller. Below, the HTTP POST method is used to prevent showing params in the data in the URL. Using the POST method is important as AJAX requests often require passing data as params to the server so that the server can determine what action it should take and/or response it should give. Those params make using the POST method preferable to the GET method.

Rails.application.routes.draw do
root 'demo#home'
post 'demo/download' => 'demo#download', as: :download
post 'demo/show_options' => 'demo#show_options', as: :show_options
post 'demo/hide_options' => 'demo#hide_options', as: :hide_options
end

Add the views and partials

Last we’ll add the views and partials.

Download Partials

The first group of partials is the download partials. Below, I simply used a single line for each partial and marked them as simple text files. While this is a trivial example, I’ve used partials like this to create downloadable results of a data analysis program that are human readable.

  • app/views/demo/downloads/_data.html.erb is simply Data view contents.
  • app/views/demo/downloads/_demo.html.erb is simply Demo view contents.
  • app/views/demo/downloads/_sample.html.erb is simply Sample view contents.
Learn Ruby on Rails? This tutorial might be helpful - Using AJAX in a Ruby on Rails AppClick To Tweet

Home and Download Options

First, we have the home view, app/views/home.html.erb, which like the rest of the app is very basic. Just a heading and a partial render.

<h1>AJAX Demo</h1>
<%= render 'demo/download_options' %> 

Next is the app/views/_download_options.html.erb partial to complete the initial view. This is just a button inside of a div with an ID to make the JavaScript easier. For more complex systems, it would be better to add the button to its own div and have this div tag initially blank. However, in the demo the two are mutually exclusive as the button is never shown at the same time as the options list. This makes it simpler to replace the button with the options and vice versa.

<div id="download_options">
 <%= button_to "View download Options", show_options_path,
 :remote => true,
 :method => "post" %>
</div>
home

Then we have the app/views/_downloads_list.html.erb partial. For this partial, a list of links to file downloads are provided with a button to hide the download options.

<h3>Your download options are: </h3>
<ul>
<li><%= link_to "Data download", download_path(data: true), :method => "get" %></li>
<li><%= link_to "Sample download", download_path(sample: true), :method => "get" %></li>
<li><%= link_to "Demo download", download_path(demo: true), :method => "get" %></li>
</ul>
<%= button_to "Hide download Options", hide_options_path,
:remote => true,
:method => "post" %>
download_options

The Hide download Options button is marked as remote so that the page won’t reload when it’s clicked. It is the clearest sign that the button is intended to use AJAX.

Javascript

The JavaScript responses are just three lines of code between the two files. While few, these lines are sufficient to hide and show content, but there are many more possible uses.

The first is app/views/demo/show_options, which shows the download options. A simple jQuery animation provides the transition. The key functionality lies in the first line. It locates the object with the ID of download_options and changes its inner HTML to be the results of the render. Note that the method j is the same as escape_javascript, which helps ensure that the JavaScript interpreter works properly after the render.

$('#download_options').html("<%= j (render 'demo/downloads_list') %>");
$('#download_options').slideDown(350);

The other is of course, app/views/demo/hide_options, where the download options are hidden. This is done by rendering the download_options partial again as it is done when the home view is rendered.

$('#download_options').html("<%= j (render 'demo/download_options') %>");

On JavaScript with Embedded Ruby

An important thing to remember with js.erb views is that you can treat them similar to html.erb as they both use embedded Ruby. For example, you can do things like use server-side conditionals (ERB) to decide what code should be sent to the client. I used this approach to have a sound played client-side depending on results from a server-side analysis.

Resources

  • JavaScript/jQuery:
    • In this tutorial you’ve learned enough to be able to start using AJAX in Rails applications. However, if you need to brush up on other base skills, Tests4Geeks has a number of tutorials on both JavaScript and jQuery.
  • GitHub, source code.
  • Heroku, demo application.
Learn Ruby on Rails? This tutorial might be helpful - Using AJAX in a Ruby on Rails AppClick To Tweet

Mykl Clason is a freelance Ruby on Rails developer specializing in converting spreadsheets into low cost web applications for personal or small business use. He  has a strong background in algorithms and data structure with over four years of programming experience between Ruby, Python, Java, and C++. 

Like the article? Share it please!

It will REALLY help us to make more content here.

  1 Comment

  1. phong   •  

    please help me uploads source code ruby on rails to server linux.i used database is mysql

Leave a Reply

Your email address will not be published. Required fields are marked *