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:
- 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.
- Readability: Separating concerns allows developers to focus on one aspect of the code at a time, making it easier to understand and work with.
- Reusability: JavaScript code is more reusable when it's not tied to specific HTML elements.
- Accessibility: Unobtrusive JavaScript ensures that your application remains accessible to users who have JavaScript disabled in their browsers.
- 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:
- Rails UJS: A library that automatically adds unobtrusive functionality to your Rails application.
- Action View Helpers: Helper methods that generate HTML markup with embedded JavaScript for you.
- Turbolinks: A library that speeds up navigation between pages by only updating the parts of the page that have changed.
- 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
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.
AJAX Link Deletion
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.