Altcademy - a Forbes magazine logo Best Coding Bootcamp 2023

What is UJS (Unobtrusive JavaScript) in Ruby on Rails?

Unobtrusive JavaScript (UJS) is a technique used in web applications that allows JavaScript code to be separated from the HTML content. This separation makes the code more maintainable, readable, and reusable. Ruby on Rails, a popular web development framework, adopts UJS for its applications. This blog post will explore the concept of UJS in Rails applications, how it works, and some examples to help you understand the benefits of using UJS.

What is UJS?

Unobtrusive JavaScript (UJS) is a web development approach that focuses on minimizing the intrusion of JavaScript code into the HTML content of web pages. By keeping the structure (HTML), presentation (CSS), and behavior (JavaScript) separate, this approach makes the code more maintainable, readable, and reusable.

UJS has several benefits:

  1. Maintainability: Separating JavaScript from HTML makes it easier to maintain the code because you don't have to search through HTML markup to find JavaScript code.
  2. Readability: Separating concerns allows developers to focus on one aspect of the code at a time, making it easier to understand and work with.
  3. Reusability: JavaScript code is more reusable when it's not tied to specific HTML elements.
  4. Accessibility: Unobtrusive JavaScript ensures that your application remains accessible to users who have JavaScript disabled in their browsers.
  5. Progressive Enhancement: UJS allows you to progressively enhance your web application, meaning that it will still work with basic functionality even if JavaScript is not available.

UJS in Rails

Ruby on Rails, a popular web development framework, embraces the concept of UJS. Rails provides various tools and helpers to make it easier for developers to create unobtrusive JavaScript in their applications.

In Rails, UJS is achieved through the use of several conventions and tools, including:

  1. Rails UJS: A library that automatically adds unobtrusive functionality to your Rails application.
  2. Action View Helpers: Helper methods that generate HTML markup with embedded JavaScript for you.
  3. Turbolinks: A library that speeds up navigation between pages by only updating the parts of the page that have changed.
  4. Stimulus: A JavaScript framework designed to work with Rails applications that helps you add interactivity to your application in an unobtrusive way.

We will explore each of these in more detail below.

Rails UJS

Rails UJS (Unobtrusive JavaScript) is a library that comes bundled with Rails and helps you create unobtrusive JavaScript in your Rails applications. It achieves this by automatically adding JavaScript functionality to HTML elements based on their attributes.

Consider the following example:

<%= link_to "Delete Post", post_path(@post), method: :delete, data: { confirm: "Are you sure?" } %>

In this example, we're using the link_to helper to create a link that deletes a post. The method: :delete attribute tells Rails that this link should send a DELETE request, and the data: { confirm: "Are you sure?" } attribute tells Rails to show a confirmation dialog before proceeding.

Rails UJS automatically handles these attributes, adding the necessary JavaScript functionality to the link without you having to write any JavaScript code yourself.

Action View Helpers

Action View Helpers are methods provided by Rails that generate HTML markup with embedded JavaScript. These helpers make it easy to create unobtrusive JavaScript in your Rails applications.

For example, the form_with helper creates a form with AJAX functionality built-in:

<%= form_with(model: @post, local: false) do |form| %>
  <%= form.text_field :title %>
  <%= form.submit "Save" %>
<% end %>

In this example, the local: false attribute tells Rails to submit the form using AJAX instead of the traditional full-page submission. Rails UJS will automatically handle the AJAX functionality for you.

Turbolinks is another tool provided by Rails that helps you create fast and responsive web applications. It works by only updating the parts of the page that have changed when navigating between pages, reducing the amount of work the browser needs to do.

By default, Turbolinks is enabled in Rails applications, and it helps you create unobtrusive JavaScript by speeding up navigation between pages and allowing you to write simpler JavaScript code.

Stimulus

Stimulus is a JavaScript framework designed to work with Rails applications. It allows you to add interactivity to your application in an unobtrusive way.

With Stimulus, you can create reusable and scalable JavaScript components that interact with your HTML elements using data attributes. This approach keeps your HTML and JavaScript code separate, making it easier to maintain and understand.

Here's an example of a simple Stimulus controller that toggles the visibility of an element:

// app/javascript/controllers/toggle_controller.js
import { Controller } from "stimulus";

export default class extends Controller {
  static targets = ["content"];

  toggle() {
    this.contentTarget.classList.toggle("hidden");
  }
}
<!-- app/views/posts/index.html.erb -->
<div data-controller="toggle">
  <button data-action="click->toggle#toggle">Toggle</button>
  <div data-toggle-target="content" class="hidden">Hello, world!</div>
</div>

In this example, we define a Stimulus controller called toggle_controller that toggles the visibility of an element with the data-toggle-target="content" attribute. The data-controller="toggle" attribute tells Stimulus to use our controller, and the data-action="click->toggle#toggle" attribute tells Stimulus to call the toggle method when the button is clicked.

Examples

Now that we have a better understanding of UJS in Rails let's look at some examples to see how it works in practice.

AJAX Form Submission

In this example, we'll create a form that submits data using AJAX. We'll start by creating a new Rails application with a simple Post model and scaffold:

rails new ajax_form_example
cd ajax_form_example
rails generate scaffold Post title:string content:text
rails db:migrate

Next, let's update the form to submit using AJAX. Open the app/views/posts/_form.html.erb file and update the form_with helper to include the local: false attribute:

<%= form_with(model: post, local: false) do |form| %>

Now, when you submit the form, Rails UJS will automatically handle the AJAX submission for you.

To update the page with the new post after submission, we'll need to create a JavaScript file that listens for the ajax:success event. Create a new file called app/javascript/packs/posts.js and add the following code:

document.addEventListener("turbolinks:load", () => {
  const form = document.querySelector("#new_post");

  if (form) {
    form.addEventListener("ajax:success", (event) => {
      const [data, status, xhr] = event.detail;
      document.querySelector("#posts").insertAdjacentHTML("beforeend", xhr.responseText);
      form.reset();
    });
  }
});

In this code, we're listening for the turbolinks:load event, which fires when the page is loaded. We then find the form element and add an ajax:success event listener. When the form is submitted successfully, we update the page with the new post and reset the form.

Finally, add the following line to the app/javascript/packs/application.js file to include the new JavaScript file:

require("./posts");

Now, when you submit the form, the new post will be added to the page without a full-page reload.

In this example, we'll create a link that deletes a post using AJAX. First, create a new Rails application with a simple Post model and scaffold:

rails new ajax_link_example
cd ajax_link_example
rails generate scaffold Post title:string content:text
rails db:migrate

Next, let's update the delete link in the app/views/posts/index.html.erb file to use AJAX. Add the remote: true attribute to the link_to helper:

<%= link_to "Destroy", post, method: :delete, remote: true, data: { confirm: "Are you sure?" } %>

Now, when you click the delete link, Rails UJS will automatically handle the AJAX request for you.

To update the page after the post is deleted, create a new JavaScript file called app/javascript/packs/posts.js and add the following code:

document.addEventListener("turbolinks:load", () => {
  const links = document.querySelectorAll("a[data-remote]");

  links.forEach((link) => {
    link.addEventListener("ajax:success", () => {
      const row = link.closest("tr");
      row.parentNode.removeChild(row);
    });
  });
});

In this code, we're listening for the turbolinks:load event and finding all the links with the data-remote attribute. We then add an ajax:success event listener to each link. When the link is clicked and the DELETE request is successful, we remove the corresponding row from the page.

Finally, add the following line to the app/javascript/packs/application.js file to include the new JavaScript file:

require("./posts");

Now, when you click the delete link, the post will be removed from the page without a full-page reload.

Conclusion

Unobtrusive JavaScript (UJS) is a powerful technique that improves the maintainability, readability, and reusability of your web applications. Rails embraces UJS and provides various tools and helpers to make it easier for developers to create unobtrusive JavaScript in their applications.

By understanding and using UJS in your Rails applications, you can create more accessible and scalable web applications that are easier to maintain and enhance.