I’ve decided to save Bootstrap and all styling for a later date. I think the look and feel would detract from my focus on making things work. So I’m going through a React on Rails course and blogging my thoughts herein.

So first things first: confusion. Apparently there are 3 gems (at least) to use React. You’ve got react-rails, react_on_rails, and webpacker. The tutorial I’m going thru uses react-rails, so that’s what I’ll be using. Before I add that to my Gemfile, let’s try to install React using a Rails generator: rails generate react:install:

Running via Spring preloader in process 35575
Could not find generator 'react:install'. Maybe you meant 'test_unit:job', 'channel' or 'assets'
Run `rails generate --help` for more options.

I just like to see error messages to get a better picture of who’s-doin-what. Let’s add that line to our Gemfile now.

gem 'react-rails'

Ok, so bundle install and rails generate react:install and let’s see what we get now:

Running via Spring preloader in process 40155
      create  app/assets/javascripts/components
      create  app/assets/javascripts/components/.gitkeep
      insert  app/assets/javascripts/application.js
      create  app/assets/javascripts/components.js
      create  app/assets/javascripts/server_rendering.js
      create  config/initializers/react_server_rendering.rb

Let’s look at the Ruby file first config/initializers/react_server_rendering.rb:

# To render React components in production, precompile the server rendering manifest:
Rails.application.config.assets.precompile += ["server_rendering.js"]

So, magic on the left adds a JavaScript file from the right. Let’s peek inside that app/assets/javascripts/server_rendering.js file:

//= require react-server
//= require react_ujs
//= require ./components
//
// By default, this file is loaded for server-side rendering.
// It should require your components and any dependencies.

And this is where I really get uneasy. Comments are supposed to be ignored, yet this kind of syntax explicitly uses them, and we get no syntax highlighting either. Looking past that momentarily, we’re just requiring (think of it as importing or extending a module, so to speak) a couple files and the components folder, which is essentially empty except for a .gitkeep file. I know there’s also a components.js file, which can be confusing. It’s the folder because of the ./.

Let’s look inside the other files, too, starting with components.js since that’s more React-specific than application.js:

//= require_tree ./components

So, it also says to require the components folder. What about application.js?

//= require react
//= require react_ujs
//= require components

The application file here requires the components file (not folder), and also requires react at the outset. So that gets our bearings around what just happened. If I had tests, hopefully they’d still pass amidst these new additions. Instead I’m going to run rails server to make sure it works for me. Ok, todo bien!

I’m going to change my home page, which is a list of Narrations, to use React. So I’ll create a new file to match my controller, app/assets/javascripts/components/narrations.jsx:

var Narrations = React.createClass({
  render: function() {
    return (
      <h1>This is my Narrations index/home page as COMPONENT.</h1>
    )
  }
})

Ok, this will just be static, but it’s a start. Now let’s jump over to our actual view: app/views/narrations/home.html.haml and plop that new component on top:

= react_component 'Narrations'

But unfortunately nothing shows in my browser. I did inspect the page and got:

<div data-react-class="Narrations" data-react-props="{}"></div>

So something React-y is working, but something else isn’t. How to fix… let’s try replicating it with a not-the-hard-way Rails app. And… that worked! So now my task is to understand who depends on what. Let’s start with application.js. Straight away at the top comparing my from-scratch app to my generated-app, I notice this line missing: //= require rails-ujs. Having the name ‘rails’ in it makes me think it’s fairly important, so let’s include that and start the app again using rails server. Nothing, but I did get a chance to compare DOMs. Inspecting each output showed that the working one had the following HTML:

<div data-react-class="Narrations" data-react-props="{}">
  <h1 data-reactroot="">Narrtions from class extends React component.</h1>
</div>

So there’s something missing that gives me the data-reactroot attribute in my tag. Oh, I forgot to add that I changed my React Component code:

class Narrations extends React.Component {
  render () {
    return <h1>Narrtions from class extends React component.</h1>
  }
}

I don’t think Turbolinks has anything to do with the React component not rendering, so I’ll add the //= require_tree . statement.

//= require rails-ujs
//= require react
//= require react_ujs
//= require components
//= require_tree .

Ok, even after that and adding Turbolinks, still no success. So let’s go up a level. We need to speak to the manager! The javascripts folder is nested in the assets folder. Its nearest neighbor of interest is the config folder, and therein lies the manifest.js file. Sounds important. Let’s dive in.

//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css

Doesn’t look too impressive, but when I create one for my from-scrath app, does it make React work? Negative. Ok, I feel like I’m not getting any closer to a solution taking this route. Inspecting the elements and viewing “Sources” in Chrome’s dev tools, I see that my from-scratch app isn’t loading my assets folder. Sensing that this has to do with the “asset pipeline”, I discovered Ryan Bates’ Railscast episode on the Asset Pipeline. So let’s look at my asset path’s between both apps running Rails.application.config.assets.paths:

This is my from-scratch app:

- "/app/assets/javascripts"

And this is the generated app:

- "/app/assets/config"
- "/app/assets/images"
- "/app/assets/javascripts"
- "/app/assets/stylesheets"

Now, I’m not using any images or stylesheets, but I suspect that the config directory is pretty important. -(24 hours later)- So I went thru a webpacker implementation, and noticed my app’s layout file differed, so I added = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' to my app/views/layouts/application.html.haml file’s head section. This tag is included in a Rails 5.1 new app, but remember I decided to do things the hard way, so it was missing for me and didn’t raise any errors! But now it works and my check in rails console for my asset paths showed the config. Read the Rails docs for javascript_include_tag here.