React with Ruby on Rails 5.1

$ ruby -v
ruby 2.4.1p111

$ rails -v
Rails 5.1.4

$ brew install yarn --without-node
$ yarn -v
1.0.2

$ rails new scoreboard --webpack=react --api

BOTH of two options. why not?

https://yarnpkg.com/en/docs/install#alternatives-tab

First let’s make API part #

we need players to render JSON

# db/seeds.rb

movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
$ rails generate model Movie name:string
$ rails db:migrate
$ rails db:seed

now ApplicationController inherits ActionController::API

# app/controllers/movies_controller.rb

class MoviesController < ApplicationController
  def index
    render json: Movie.all
  end
end

and route

# config/routes.rb

  get "/movies", to: 'movies#index'
$ rails server -p 3001

on different terminal window,

$ curl 'http://localhost:3001/movies'
[{"id":1,"name":"Star Wars","created_at":"2017-09-15T23:47:07.706Z","updated_at":"2017-09-15T23:47:07.706Z"},{"id":2,"name":"Lord of the Rings","created_at":"2017-09-15T23:47:07.710Z","updated_at":"2017-09-15T23:47:07.710Z"}]

Looks good.

make React page #

app/javascript/packs/application.js file says:

To reference this file, add <%= javascript_pack_tag ‘application’ %> to the appropriate layout file.

so we need views directory.. but already did --api

$ rails generate controller home index

but this has to be changed into this

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
  end
end

class HomeController < ActionController::Base
  def index
  end
end

open localhost:3001/home/index

now we have ActionController::UnknownFormat error correctly.

make app/views/home/index.html.erb file

there’s no error

we need this file (a view template) for React

again, app/javascript/packs/application.js file says:

To reference this file, add <%= javascript_pack_tag ‘application’ %> to the appropriate layout file.

# app/views/home/index.html.erb

<%= javascript_pack_tag 'application' %>

open localhost:3001/home/index and see

Hello World from Webpacker

and we have only one this page so make it root:

remove

  get 'home/index'

add

  root 'home#index'

now open localhost:3001/ and see

Hello World from Webpacker

on developer tools console. (type cmd + option + i and then Console tab)

it was successful to me.

List movies #

I wrote simple Header and Movie component. It looks like componentDidMount does the job.

// app/javascript/packs/application.js

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import createReactClass from 'create-react-class'

var MOVIES = [];

function Header(props) {
  return (
    <div className="header">
      <h1>{props.title}</h1>
    </div>
  );
}

Header.propTypes = {
  title: PropTypes.string.isRequired
}

function Movie(props) {
  return (
    <div className="movie">
      <div className="movie-name">
        {props.name}
      </div>
    </div>
  );
}

Movie.propTypes = {
  name: PropTypes.string.isRequired
}

var Application = createReactClass({
  propTypes: {
    title: PropTypes.string
  },
  getDefaultProps: function() {
    return {
      title: 'Movie Theater'
    };
  },
  getInitialState: function() {
    return {
      movies: this.props.initialMovies
    };
  },
  componentDidMount: function() {
    var request = new Request('/movies', {
      method: 'GET',
      headers: new Headers({
        'Content-Type': 'application/json'
      })
    });
    fetch(request).then(function(response){
      return response.json();
    }).then(function(movies){
      this.setState({
        movies: movies
      });
    }.bind(this)).catch(function(error){
      console.error(error);
    });
  },
  onChange: function(e) {
    e.preventDefault();
    this.setState({
      movie: e.target.value
    })
  },
  render: function() {
    return (
      <div className="scoreboard">
        <Header title={this.props.title} />
        <div>
          {this.state.movies.map(function (movie, index) {
            return (<Movie name={movie.name} key={movie.id} />);
          }.bind(this))}
        </div>
      </div>
    );
  }
})

copy following from app/javascript/packs/hello_react.js file

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Application initialMovies={MOVIES} />,
    document.body.appendChild(document.createElement('div')),
  )
})

It’s just working! Next time I’ll do delete or create, update movies.

 
2
Kudos
 
2
Kudos

Now read this

install zsh ubuntu 14.04 LTS

What I did is… open ubuntu software center and install “Shell with lots of features” (the first one on top when search by “zsh”) then did this (alternate way to install zsh) and, got “don’t have to” message. $ sudo apt-get update... Continue →