Adding Custom JavaScript in Rails 6

Felice Forby - Aug 21 '19 - - Dev Community

In Rails 6, JavaScript assets are no longer included with the app/assets/ directory and instead have been moved into a separate directory app/javascript handled by Webpacker. That's great, but when I wanted to add some custom javascript of my own, there wasn't any clear documentation that described how it should be done.

After some experimentation and digging around on the internet, here are a couple of methods that seem to work. Note that I'm not a javascript expert by any means, so if there is a better way—or other ways that I'm missing—let me know in the comments!

Method 1: Create a custom directory and require it in application.js

If you look at application.js, the comment at the top suggests that you "place your actual application logic in a relevant structure within app/javascript and only use these pack files to reference that code so it'll be compiled."

// app/javascript/packs/application.js

// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
Enter fullscreen mode Exit fullscreen mode

You can set this up by adding a custom directory within the app/javascript/, e.g. custom/, and then require the files within in application.js.

For example, if you have a javascript file named home.js in the app/javascript/custom/ directory, you can get it to load with require():

// app/javascript/packs/application.js

// ...

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

require("custom/home")
Enter fullscreen mode Exit fullscreen mode

Since it's required in application.js, the custom javascript will be compiled along with all the other javascript into a timestamped application.js file that looks something like application-a03d1868c0a3f825e53e.js.

This is loaded by the <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> tag in the app/views/layouts/application.html.erb, automatically created when you make a new Rails app.

For a cleaner look, you could also name the javascript file index.js and require it with a simple reference to the directory like require("custom") because require() looks for an index.js file when given a path to a directory (if there is no index.js, it will fail).

Method 2: Add custom JavaScipt within the app/javascript/packs directory

If for some reason you don't want to create another directory, you could opt to add custom javascript files within the app/javascript/packs directory. Then, require the files in application.js with require().

For example, if you have a file named custom.js in app/javascript/packs, require it like below and it will be compiled into the timestamped application.js file with all the other javascript:

// app/javascript/packs/application.js

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

require("packs/custom")
Enter fullscreen mode Exit fullscreen mode

Method 3: Using javascript_pack_tag for separate JavaScript files (packs)

If you don't want your custom javascript to be compiled into the application.js with everything else, you can get Rails to compile it into a separate file, or "pack."

To do so, add a custom file within app/javascript/packs, e.g. custom.js, then use the javascript_pack_tag helper where the file is needed in the views like so: <%= javascript_pack_tag 'custom' %>

The custom javascript will be compiled separately from the rest of the javascript into a timestamped custom.js that looks something like this: custom-a03d1756c0a3f825e53e.js

Here's how it might look if you added the custom javascript just before the ending body tag in the layouts/views/application.html.erb:

# app/layouts/views/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>My App</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body class="<%= controller_name %> <%= action_name %>">
    <%= render 'layouts/header' %>

    <%= yield %>

    <%= render 'layouts/footer' %>

    <%= javascript_pack_tag 'custom' %>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Thanks for reading!

. . . . . . . . . . . . . . . . . . . . . . . . .