Unobtrusive JavaScript in Rails
JavaScript is a very powerful language; for me, it rules the web. One of the most popular use of JavaScript is updating the content of a page without having to reload the page. This article will focus on how to achieve this in Rails.
I recently picked up Ruby and to familiarise myself with the language, I decided to build a little app using Ruby on Rails. While working on the project, the need to render content on a page without reloading came up. It was a bit frustrating trying to get an article that explains this concept to a newbie, so I decided to write about it.
With most JavaScript codes out there, one would probably need to retrieve data from the server and use JavaScript to manipulate the data on the page but with Rails, it is different as I have come to know.
Rails’ AJAX..
Rails uses a technique called “Unobtrusive JavaScript” to handle attaching JavaScript to the DOM. According to the docs:
We call this ‘unobtrusive’ JavaScript because we’re no longer mixing our JavaScript into our HTML. We’ve properly separated our concerns, making future change easy.
Let’s look at a simple example: Lets assume we have a UsersController
and a resource route /user/:name
that links to the controller’s index
action, we can perform a JavaScript action on a page from the controller.
In the UsersController
, add the following code:
class UsersController < ApplicationController
def index
render js: "alert('The username to be displayed is: #{params[:name]}')"
end
end
In your welcome
view page, add the following code which should create a “Display a name”
link on the page.
<%= link_to 'Display a name', display_path('Troy34'), remote: true %>
Adding remote:true
to the link tag tells Rails that you want to make an AJAX request and when we click on the link, a JavaScript alert should pop up on the page displaying The username to be displayed is: Troy34
. It’s that simple and it gets even magical in our next example.
Just like me, I’m sure you don’t just want to display an alert to your users. Now let’s assume the UsersController
’s index
action makes some important query and returns an array of users, we would like to display this list of users on our page. For the purpose of this example, I’ll list the files we’ll be referring to, just so things don’t get confusing.
Welcome Page:
The page with the“Display a name”
link to make the AJAX request.index action:
The action in theUsersController
that queries the database and renders the data.index template:
The JavaScript file that targets the element on the page where the list of names should be rendered(located in the user view folder/app/views/users/index.js.erb
)._index partial:
The file that contains the template to render the names of the users(located in the user view folder as/app/views/users/_index.html.erb
)
Back to our second example. From the example above, we already have a link on our Welcome Page
that calls the index action
of the UsersController
. So next, we modify the code in our controller:
class UsersController < ApplicationController
def index
@users = User.all # a random query that returns an array of imaginary users
respond_to do |format|
format.js
end
end
end
In our index template
, we add the following code:
$(‘#user-list’).html(“<%= j render(‘index’, users: @users) %>”)
In the above code, we use jQuery to target an imaginary div
with the id
of user-list
where we want to display the list of users. Then we render the content created by a partial called “show”
as HTML inside that div
. The j
is an alias for the Rails method escape_javascript
which escapes carriage returns, single and double quotes for JavaScript segments. render(‘index’, users: @users)
looks for a partial file named “index”
(which we named _index
)and passes our @users
instance variable to it as a variable called users
.
In our _index partial
, we add the following code:
<% if !users.empty? %>
<ul>
<% users.each do |user| %>
<li><%= user.name %></li>
<% end %>
</ul>
<% else %>
<div>
<p>User not found</p>
</div>
<% end %>
Our _index partial
expects a variable called users
(which is coming from the index template
). It then loops through our users array and generates a list of users which is then inserted into our user-list
div.
So lets run through the events from the point of clicking our “Display a name”
link on the index page:
- Clicking the button makes an AJAX request to the
index action
of theUsersController
- The
UsersController
’sindex action
makes the query, gets the response from our server and sends it out asjs
- Rails automatically (magically) looks for a template file that corresponds with the
index action
which isindex.js.erb
- The
index template
targets an element on the page and renders a partial and passes the users array to the partial - The partial loops through the user array and creates the list of users that is rendered on the page
I’m sure right now, you’re marvelling at the elegance at which this was done. This helps you do a lot of amazing things without messing up your view and if the need to change things ever arises, you can do all that in one place.
I hope this has helped you understand how Unobtrusive JavaScript works in Rails. Please 👏 and share.
Thanks!