Starting a Rails application with React

Quickstart guide on how to set up a Rails application with React.


Starting a new application

The concept of using React inside a Rails application is all about converting necessary data to JSON and using embedded Ruby to place it in your views. That data is then parsed in JavaScript and can be used by React components. If you already have a Rails application, skip to Adding React to an existing application and if not, start by creating your rails app (I set up this one with a PostgresQL database) with Webpack React. You should also skip turbolinks as this can cause issues later in production.

rails new appname --webpack=react -d postgresql --skip-turbolinks

That's it! Your Rails application is now set up to use React. Read on to find out how to actually use it within your application. TL;DR: You can create new components inside app/javascript/packs and include them in views with <%= javascript_pack_tag 'component_name' %>. Take care not to add .jsx at the end of the component name as Rails already does this for you (just like a partial!).

Adding React to an existing application

If you've already started your Rails application then don't panic! You can manually make all of the changes that the generator above does for you. Start by adding gem 'webpacker' into your Gemfile and run bundle install in your terminal. Next we need to run the webpacker installer and the react webpacker installer:

rails webpacker:install
rails webpacker:install:react

Finally, you'll want to remove turbolinks, which you can do in 3 easy steps:

Using React inside your application

React applications obviously rely on props, but there's no intuitive way to do this when using React inside a Rails application. My preferred approach is to create your component container element with an erb <%= content_tag %> and give it a data attribute that includes all the required data. For the purpose of this explanation we will generate a Post model and a Pages controller with an index action, but you can modify these processes to fit any existing app structure.


First things first, let's generate that posts model. For now, we're just going to add one string column called 'text'. Run rails g model post text in your terminal and then run rails db:migrate. Note: If you started a new application, you will of course need to run rails db:setup or rails db:create before you migrate.


Next, we'll generate the Pages controller with the index action and view: rails g controller pages index. After that's finished, take a look inside your Pages controller and set an instance variable to all of your posts like so:

class PagesController < ApplicationController 
  def index 
    # Add the line below
    @posts = Post.all 
  end 
end 

Then go to the pages/index.html.erb view and copy and paste the below code into it. All this does is generates a <ul> element with a data attribute containing your @posts variable and inside it we make a call for a React component we'll create in a moment.

<!-- inside pages/index.html.erb -->
<%= content_tag :ul, id: "something", data: {posts: @posts}.to_json do %>
  <%= javascript_pack_tag 'list_posts' %>
<% end %>  

Then you can create a list_posts.jsx file in app/javascript/packs to render your new React component. If you have already configured your Rails application to use ES6, you can use ES6 style React code, however as standard you will need to use ES5 JavaScript like so:

import React from 'react'
import ReactDOM from 'react-dom'

function ComponentName(props) {
  var items = [];
  for (var i = 0; i < props.posts.length; i++){
    items.push(<li>{ props.posts[i]['text'] }</li>);
  };
  return items
};

var data = JSON.parse(document.getElementById('something').getAttribute('data'));

ReactDOM.render(
  <ComponentName {...data} />,
  document.getElementById('something')
);

Now to check it all works, open up a rails console with rails c and create a post: Post.create(text: "This is my text"). Now boot up your local server and go to /pages/index and you should see a list containing the new post you just created.