Photo by Jackson So on Unsplash

Don’t write inline JavaScript in Embedded Ruby (ERB)

Tomas Barry
Butternut Engineering
4 min readNov 18, 2021

--

Embedded Ruby, referred to as ERB from here on out, is a templating language based on Ruby. ERB allows for a developer to create a document with HTML-like syntax with the added benefit of being able to use Ruby code in your HTML. Take the following HTML for example:

<ol>
<li>Labrador Retriever</li>
<li>Jack Russell Terrier</li>
<li>Cavoodle</li>
<li>Australian Shepherd</li>
<li>Great Dane</li>
<li>Pomeranian</li>
<li>Springador</li>
</ol>

You could see this HTML getting pretty long if we kept adding new dog breeds. Also, consider the git diff if we were to add classes to the li elements. Well, with ERB, we can make things a bit more succinct:

dog_breeds = [
'Labrador Retriever',
'Jack Russell Terrier',
'Cavoodle',
'Australian Shepherd',
'Great Dane',
'Pomeranian',
'Springador'
].freeze
<ol>
<%= dog_breeds.map do |dog_breed| %>
<li>
<%= dog_breed %>
</li>
<% end %>
</ol>

Now that we’ve explained what ERB is, let’s talk about what often happens once you start developing pages with a bit more complexity.

The <script> tag

JavaScript makes web pages dynamic. It gives them life. We can embed JavaScript directly into our HTML (and our ERB) by using the <script> tag. Let's say for instance we wanted to be sure that the dog breeds in our <li> tags had each letter capitalized. We could do something like:

dog_breeds = [
'Labrador Retriever',
'Jack Russell Terrier',
'Cavoodle',
'Australian Shepherd',
'Great Dane',
'Pomeranian',
'Springador'
].freeze
<ol>
<%= dog_breeds.map do |dog_breed| %>
<li>
<%= dog_breed %>
</li>
<% end %>
</ol>
<script>
const listItems = document.getElementsByTagName('li')
listItems.map((listItem) => {
const innerText = listItem.innerText
listItem.innerText = innerText.split(' ').map((word) => word.toUpperCase())
})
</script>

That’s pretty straightforward, if not a bit of an odd thing to write some JavaScript for (especially since we could have done it in Ruby). Can you think of any issues with the above?

The dangers of the <script> tag

Unfortunately, not all browsers support the same JavaScript features. caniuse.com is a great resource for testing whether or not some JavaScript feature that you want to use is supported. This is part of the reason why at Butternut we use a polyfill, Webpack, and Babel. As developers, we shouldn’t have to know what JavaScript features are and are not supported, we should be able to write JavaScript using the latest features and let our tools polyfill what we have written to ensure that it is supported across different browsers and browser versions.

Looking a bit more closely at the JavaScript that I have written in the <script> tag, the very first line contains JavaScript that isn't universally supported. getElementByTagNameisn't supported by older versions of Safari. Now, you may not want to support these very old versions of Safari and you may not support browsers like Internet Explorer but the fact remains that there is a risk that you will inadvertently use JavaScript that is not compatible with a browser or browser version that you do support. This will cause you issues and these are issues that you shouldn't have to care about.

What should I do instead?

Whatever your build pipeline is, whether you use Babel, or Browserify, or anything else, you should ensure that all of your JavaScript gets transpiled and bundled through the same pipeline. What this effectively boils down to is that you should not use the <script> tag in your ERB files (the exception here is pre-transpiled JavaScript from a vendor like Stripe or Segment).

That’s it, just don’t write inline JavaScript in your ERB.

The question now is, how do I get JavaScript into my webpages? You should look to include JavaScript through a javascript_include_tagor a javascript_pack_tag (or similar) depending on what your JavaScript pipeline is.

How can I make sure I don’t use a <script> tag?

Like most things, if you can implement automated rules to your codebase you should. Linters are a great way of keeping code consistent without having to pour over every single line yourself. Luckily, there is an ERB linter that you can use (there is even an ERB linter plugin for Sublime Text as well as other code editors). Fortunately, there is a rule that you can enable that will prevent someone from using a <script> tag. Just create a .erb-lint.yml file at the root of your project and add the following:

linters:
AllowedScriptType:
enabled: true
disallow_inline_scripts: true

In summary, by ensuring that JavaScript in your ERB file is transpiled:

  • The latest and greatest JavaScript features are available
  • You can make use of TypeScript or Flow
  • Linters can be run on your JavaScript
  • Browsers not supporting certain features of JavaScript is no longer a concern

--

--