First Step for React.js on Rails

This article describes how to start React on Rails.

๐ŸŽ‰ Instration Node with Mac Homebrew

brew upgrade
brew install node

๐Ÿ Creating React Sample App

npm install -g create-react-app
create-react-app hello-world
cd hello-world
npm start

๐Ÿฎ Using React on Rails

In this section, we are using RubyGem react_on_rails.

At first, add the following to your Gemfile and bundle install:

gem 'react_on_rails'

Commit this to git and please run following commands:

# Run the generator with a sample "Hello World" App with React.js
rails g react_on_rails:install

# Bundle && NPM install:
bundle && npm install

# Start your Rails server:
foreman start -f

Please see http://localhost:3000/hello_world.

All JavaScript in React On Rails is loaded from npm: react-on-rails.
To manually install this, please execute following command like this:

cd client && npm i --saveDev react react-on-rails react-helmet nprogress

๐Ÿฏ Controller

Supporting following flow:

  1. Return HTML in first request
  2. In page transition, return JSON
  3. Do not show JSON when returning with browser back
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception


def _action_path

def _common_props
{ actionPath: _action_path }

def _render_for_react(props: {}, status: 200)
if request.format.json?
response.headers['Cache-Control'] = 'no-cache, no-store'
response.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT'
response.headers['Pragma'] = 'no-cache'
json: {
rootProps: _common_props.merge(props)
status: status
html: view_context.react_component(
props: {
rootProps: _common_props.merge(props)
layout: true,
status: status

Usage example is as follows:

class ArticlesController < ApplicationController
# GET /
def index
props: {
articles: Article.limit(20)

๐ŸŽƒ JavaScript

Entry Point

Entry point of shared JavaScript code is like this:

// client/entry_points/main.js
import ReactOnRails from "react-on-rails";
import Router from "../components/Router";

ReactOnRails.register({ Router });


  1. Router selects Component by actionPath
  2. Display progress bar during page transition
  3. Scroll to a top of a page after page transition
  4. Adjust browser history using pushState / popState
import React from "react";
import NProgress from "nprogress";

import Articles from "../components/Articles"

export default class Router extends React.Component {
static propTypes = {
rootProps: React.PropTypes.object,

static childContextTypes = {
onLinkClick: React.PropTypes.func,

componentDidMount() {
window.addEventListener("popstate", () => {
this.transitTo(document.location.href, { pushState: false });

constructor(...args) {
this.state = {
rootProps: this.props.rootProps,

getComponent() {
switch (this.state.rootProps.actionPath) {
case "articles#index":
return Articles;

getChildContext() {
return {
onLinkClick: this.onLinkClick.bind(this),

onLinkClick(event) {
if (!event.metaKey) {
const anchorElement = event.currentTarget.pathname ? event.currentTarget : event.currentTarget.querySelector("a");
this.transitTo(anchorElement.href, { pushState: true });

transitTo(url, { pushState }) {
url: url,
dataType: 'json',
cache: false,
success: function(props) {
if (pushState) {
history.pushState({}, "", url);
this.setState({rootProps: props.rootProps});
if(typeof window !== 'undefined') {
window.scrollTo(0, 0);
error: function(xhr, status, err) {
console.error(url, status, err.toString());

render() {
const Component = this.getComponent();
return <Component {...this.state.rootProps} key={this.state.requestId} />;


When a user clicks a link, a client communicates with the server with XHR and post a state to Router.

So I use the original Link tag instead of a tag.

import React from "react";

export default class Link extends React.Component {
static contextTypes = {
onLinkClick: React.PropTypes.func,

onClick(event) {

render() {
<a onClick={this.onClick.bind(this)} {...this.props}>

Link example is as follows:

<Link href="/">txt</Link>

๐Ÿ—ป Title/Meta Tags

import React from "react";
import Helmet from "react-helmet";

import {siteName, siteBaseUrl} from "../constants/service";

export default class Articles extends React.Component {
pageUrl() {
return siteBaseUrl + "/articles";

pageTitle() {
return "huga";

pageDescription() {
return "hoge";

render() {
{rel: "canonical", href: this.pageUrl()},
{rel: 'alternate', href: this.pageUrl()},
{property: "og:url", content: this.pageUrl()},
{property: "og:title", content: this.pageTitle()},
{property: "og:description", content: this.pageDescription()},
{name: "description", content: this.pageDescription()},

๐Ÿค” Run npm install in ElasticBeansTalk

This is a script to use webpack in deploy process of ElasticBeansTalk.
To use webpack you need to run npm install beforerake assets: precompile.
(10 is depend on each environment, so please fix it.)

"/opt/elasticbeanstalk/hooks/appdeploy/pre/" :
mode: "000744"
owner: root
group: root
content: |
#!/usr/bin/env bash
set -xe
EB_APP_STAGING_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_staging_dir)
npm install
encoding: plain

๐Ÿšœ Special Thanks

This article has created by the following Japanese articles. Thank you very much, @r7kamura!

๐Ÿ˜ผ Sample App

๐Ÿ–ฅ Recommended VPS Service

VULTR provides high performance cloud compute environment for you. Vultr has 15 data-centers strategically placed around the globe, you can use a VPS with 512 MB memory for just $ 2.5 / month ($ 0.004 / hour). In addition, Vultr is up to 4 times faster than the competition, so please check it => Check Benchmark Results!!