Using jQuery with Rails: How To

  

using jquery with railsJavaScript allows you to update HTML without reloading the page. This makes the interaction with your website faster as you only need to upload some parts of the page instead of the whole page. jQuery is a popular JavaScript library used by a lot of developers regardless of the language or framework used.

This tutorial focuses on using jQuery with Rails. This is for you if you are:

  • a Rails developer new to jQuery
  • familiar with jQuery but new to Rails

We'll talk about:

Creating a new Rails app
Effects
Events
Selectors
JavaScript Console
Notes
Conclusion

jQuery With Rails Step By Step

jQuery provides a lot of features but we'll start with the basics. We'll discuss Effects, Events, and Selectors. In the future, I will dedicate a whole post for Ajax which is used to make remote requests.

There are other JavaScript libraries or frameworks that can be used with Rails like Turbolinks, React, Vue, or Ember. At some point, your app might need one of these but today we'll discuss jQuery. If you want to suggest a topic for a future blog post, please leave a comment below.

Create the Rails app

You can follow along and start from scratch or you can clone the full application here.

Generate a new Rails 5.1 application named tutorialapp. This is a simple app that displays a list of tutorials saved in the database.

rails new tutorialapp --skip-turbolinks

Starting Rails 5.1, jQuery is not included by default. Let's add it on the Gemfile.

gem 'jquery-rails'

The jquery-rails gem contains the jQuery files. Install the gem with

cd tutorialapp
bundle install

To include the jQuery files in our application, we will require a few files on app/assets/javascripts/application.js. We'll also remove rails-ujs since we're using jquery_ujs for the same purpose.

//= require jquery3
//= require jquery_ujs
//= require_tree .

Now, let's generate the tutorial resource which will create the Tutorial model and controller and update the routes. The model will have a title and a url, both Strings.

rails g resource tutorial title:string url:string

On app/controllers/tutorials_controller.rb, add the index action.

def index
  @tutorials = Tutorial.all
end

On the index view app/views/tutorials/index.html.erb, display all the tutorials.

<h1>Tutorials</h1>

<ul>
  <% @tutorials.each do |tutorial| %>
    <li><%= tutorial.title %></li>
  <% end %>
</ul>

Before we start the application, let's add a few records so our app has data to display. Add the following to db/seeds.rb.

Tutorial.create(title: 'Encrypted Rails Secrets on Rails 5.1', url: 'https://www.engineyard.com/blog/encrypted-rails-secrets-on-rails-5.1')
Tutorial.create(title: 'Using Docker for Rails', url: 'https://www.engineyard.com/blog/using-docker-for-rails')
Tutorial.create(title: 'Running a Rails App in Kubernetes', url: 'https://www.engineyard.com/blog/kubernetes-tutorial-running-a-rails-app-in-kubernetes')

Then run the migration and seed commands.

bin/rake db:migrate
bin/rake db:seed

Start the application and go to the tutorials index page.

bin/rails server

On your browser, go to http://localhost:3000/tutorials

This is a standard Rails application so far. Now let's add some jQuery code. We'll add a Hide link beside each tutorial. When you click Hide, the tutorial will be hidden without reloading the page. We will not delete the tutorial from the database for now.

Change the view app/views/tutorials/index.html.erb to include the Hide link

<h1>Tutorials</h1>

<ul>
  <% @tutorials.each do |tutorial| %>
    <li><%= tutorial.title %> <%= link_to "Hide", "", class: 'hide', data: {'js-hide-link' => true} %></li>
  <% end %>
</ul>

We use a data attribute js-hide-link which we'll use in our JavaScript code. The code above will result in

<a data-js-hide-link="true" href="">Hide</a>

On application.js,

$(document).ready(function() {
  $('[data-js-hide-link]').click(function(event){
    alert('You clicked the Hide link');
    event.preventDefault(); 
  });
}

Let's take a look at this code line by line. The whole thing is wrapped around $(document).ready. We need this so that our JavaScript code gets loaded after the DOM is ready.

Now we get all elements that has the data-js-hide-link attribute with $('[data-js-hide-link]') and bind an event handler using .click(). When the link is clicked, the function will be called.

Inside the function, I used an alert to visually confirm that our code works. We'll remove this later.

We call event.preventDefault() to prevent the page from reloading as the link points to the same page. A new request will be made and the page will load again without this code.

Reload the page, you don't need to restart the Rails app. When you click Hide you should see an alert. When that's working, replace the alert with this code

$(this).parents('li').hide();

$(this) refers to the a element and parents('li') refers to the li element. hide() is the jQuery method to hide the element from the page.

Try it. Clicking Hide should hide the tutorial from the page.

Effects

If you want to use effects other than hide(), check out the API documentation for Effects. You can use for example, fadeOut to hide the tutorial gradually.

$(document).ready(function() {
  $('[data-js-hide-link]').click(function(event){
    $(this).parents('li').fadeOut(2000);
    event.preventDefault(); 
  });
}

Events

click isn't the only event you can bind to. The API documentation for Events lists all the events. Below, we will add a text field and add JavaScript code that fires up after you type on the text field.

On the view app/views/tutorials/index.html, add a search text field.

Search <%= text_field_tag 'search', '', data: {'js-search' => true} %>

On application.js, inside $(document).ready(function() { add

  $('[data-js-search]').change(function(event) {
    search_term = $(this).val();
    alert('You are searching for ' + search_term);
  });

When you type some text and press tab or click anywhere on the screen, an alert will show up and display the text you typed on the text field. The text is retrieved using val(). We will not build the actual search functionality. The search text field is only used to demonstrate the change() event.

Selectors

So far, we select elements using the data attribute like $('[data-js-search]'). There are multiple ways to select elements as you can see on the API documentation for Selectors.

In fact, most tutorials out there use classes or ids. The search text field above has an id of search. The html produced by text_field_tag is

Search <input type="text" name="search" id="search" value="" data-js-search="true" />

Your JavaScript code can then use $('#search').change(function(event) { .... You can (but shouldn't) even remove the data attributes since you can find the element using the id.

The Hide links above have a class of 'hide'. You can use $('.hide').click(function(event){. You can also use $('a').click(function(event){ to select all <a> elements.

To summarize, you can use # for ids, . for classes, and the element name a inside $(). However, it is recommended that you use data-* attributes like $('[data-js-search]') instead of ids and classes. I only showed you the selectors for ids and classes because most tutorials will use these.

Ids and classes are used to style HTML using CSS. We can style all elements with the .hide class to have a color of red by adding the code below on app/views/stylesheets/application.css.

.hide {
  color: red;
}

Using a class selector $('.hide') works but then you'll be using the hide class for both CSS and JavaScript. If you don't like to use a data attribute and prefer classes, you should at least add a different class like js-hide to have separate classes for CSS and JavaScript.

JavaScript Console

When writing code in JavaScript, it is helpful to look at the JavaScript Console for possible errors. In Chrome, you can open the JavaScript Console by going to View then Developer.

You can use console.log to log information on the console. Another option is to add debugger. We use both options below.

$(document).ready(function() {
  $('[data-js-hide-link]').click(function(event){
    console.log('You clicked the Hide link');
    debugger
    $(this).parents('li').fadeOut(2000);
    event.preventDefault(); 
  });
}

When you click Hide, the debugger will pause the script execution and show you the line where you called debugger under the Sources tab. You can inspect the local and global variables on the right side.

Click the Console tab to go back to the JavaScript Console. You will see 'You clicked the Hide link'. You can also use $(this) which points to the a element at this point as you're inside the function passed to click(). Type $(this).parents('li').fadeOut(2000); and $(this).parents('li').fadeIn(2000); and you will see the li element fade out and in.

When you're done debugging, click the Resume button under the Sources tab or F8 to resume the script execution.

Notes

  • The jquery-rails gem contains all 3 jQuery versions. You can use jQuery 1, 2, and 3 by requiring jquery, jquery2, and jquery3 on application.js respectively. You can view the versions included in the gem on this page.
  • We put the JavaScript code on application.js and CSS code on application.css but in your application, you should put them on their respective files.
  • The jquery-rails gem was removed as a dependency starting Rails 5.1. It does not mean that jQuery is not recommended to be used. jQuery as a default library is mainly used for Unobtrusive JavaScript which we'll take more about in a future post.
  • The use of data attributes instead of classes is documented more on this repo. Thank you to Rico Sta. Cruz for creating this guide.

Conclusion

This tutorial got you started with using jQuery on your Rails application. We discussed data attributes, using them on your Selectors, binding to Events, and using Effects when the Events are triggered. There are more things we can discuss but you should now be able to go to the jQuery API documentation or follow other jQuery tutorials for additional learning.

Was this tutorial helpful to you? Do you have suggestions on future topics? We like to hear from you in our Comments section.

Free Ebook:
Should I Hire DevOps or Outsource to a Provider?

You have to invest in your infrastructure: Do you hire DevOps for this critical function, assign it to your already overworked engineers, or outsource to a provider that offers full-stack capabilities?

Should I Hire DevOps?

Christopher Rigor

 
DevOps Support Manager, Asia-Pacific at Engine Yard. Organizer of @RubyConfPH. Speaker. Interested in automation, Kubernetes, Docker, Deis, ops, Ruby.
Find me on:

Comments

Subscribe Here!