Ruby on Rails 5.1+ & React: The Easy Way

Ruby on Rails 5.1+ & React: The Easy Way

This is a hard one to get right, and there are so many ways of doing it. In this tutorial, I’ll be getting React running with Webpack and the Babel loader on a Rails 5.1+ application. The React-Rails gem is excellent to get some basic React action going on in your rails application, however, it’s not ideal when you’re dealing with several components and trying to manage the scope of each. It’s especially tough to work with when you’re trying to include NPM modules — not the easiest task when you’re dealing with the pre-canned Rails Asset Pipeline.


Initial Setup

In your Gemfile, add react-railswebpacker gems with

gem webpacker
gem react-rails

You will also need run the following:

bundle install
rails webpacker:install
rails webpacker:install:react
rails generate react:install

Heads Up: If you don’t have “Yarn” installed, you’ll probably get a warning about it. Use your system package manager to install it. You may also need to run yarn update

You might be wondering how to deal with the whole Babel part. Thankfully the latest Webpacker has been bundled with it. All of Babel’s settings should be defined in the .babelrc file.

If you’re using Rails 5.2+, make sure to add this to config/initializers/content_security_policy.rb:

if Rails.env.development?
    p.script_src :self, :https, :unsafe_eval
    p.script_src :self, :https

Getting it Working

To require components in the components you’re working on, just import it from wherever you need to. Components will be generated and found in the /app/assets/javascripts/components directory.

You can generate them with this command:

rails g react:component HelloWorld greeting:string

For ES6 syntax, simply add “--es6” to the end.

rails g react:component HelloWorld greeting:string --es6

Fortunately, if you install a package with npm install --save mypackagename, you will find the file in node-modules directory of your project. You might be wondering how this hooks up to your assets pipeline; luckily, the answer can be found in config/initializers/assets.rb. In normal people language, your default assets path gets that node-modules directory added to it, so your components will now be included from here.

# Be sure to restart your server when you modify this file.

# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'

# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
# Add Yarn node_modules folder to the asset load path.
Rails.application.config.assets.paths << Rails.root.join('node_modules')

# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )

Now What?

According to our config file, everything Webpack can see will get bundled into a monolithic javascript file located at app/assets/javascripts/bundle.js. You can view this with:

less app/assets/javascripts/bundle.js

If there's ever any question whether or not something was included here, you can easily find that chunk of code by searching with a forward slash (/) and typing in that block of text.

If you're like me, you keep a ruby server window open next to your code. If you're using iTerm2 or Terminal, awesome... Open up a new tab and type webpack -w -d to get webpack to recompile every time any changes are made. Leave this process running if you want your code compiled every time you save. It's also useful to keep running in plain sight to catch errors before you refresh your browser.

webpack -w -d

Not only does this run changes every time something is compiled, but it also allows you to debug without driving yourself insane. Especially if you're writing code in ES6 while your browser is displaying ES5.

Provided this is the method you want to go with, your rabbit hole of components can be initialized in any .erb template you want. Simply drop this helper tag in your template to initialize your component.

<%= react_component("HelloWorld", { greeting: "Hello" }) %>

"How About a Working Example, You Unhelpful Jerk?"

Continue along to the tutorial located here: