Ruby
JavaScript
Rails
Node.js
reactjs

JavaScript on Node.js X Ruby on Rails

More than 3 years have passed since last update.

JavaScript はWebアプリケーションの特にフロントエンドで大切な存在です。

Rails もWebアプリケーションの開発で便利な機能がたくさんあります。

この2つのメカニズムを使うのに、どちらかによせて混ぜ合わせるのではなく

それぞれに分離して、2つのメカニズムをクロスして使うほうが幸せを感じます。

Ruby on Rails に慣れていない、JavaScript のエンジニア向けに View

ReactRedux を利用した JavaScriptRails をクロスする手順を記します。

このサンプルはGitHubで公開しています。


Environment


  • Ruby: v2.2.3

  • Rails: v4.2.5

  • Node.js: v4.2.1

  • React: v0.14.0

  • Redux: v3.0.4

  • webpack: v1.12.9

  • yo: v1.5.0

  • generator-redux: v0.3.1



Rails new



  • rails new のコマンドでWebアプリケーションが簡単に構築できます。

$ rails new rails-react-example

$ cd ./rails-react-example


Yeoman



  • YeomanGenerator を利用して Redux を構築します。

$ npm install --global yo

$ npm install --global generator-redux



  • Phoenix の様に JavaScript/private/static に設置します。


  • yo redux のコマンドで対話式にWebアプリケーションが構築できます。


  • Rails3000 ポートを標準で利用するので、ここでは 4000 を設定します。

$ mkdir -p ./private/static

$ cd ./private/static
$ yo redux
? What's the name of your application? static
? Describe your application in one sentence: ...
? Which port would you like to run on? 4000
? Install dependencies? No


npm



  • package.json ファイルをルートディレクトリにコピーします。


  • npm install コマンドで JavaScript のライブラリがインストールされます。

$ cd ../../

$ cp ./private/static/package.json .
$ echo /node_modules >> .gitignore
$ npm install



  • package.jsonscripts のコマンドに cd ./private/static && を付加します。


package.json

"scripts": {

"start": "cd ./private/static && DEBUG=true node server.js",
"build": "cd ./private/static && webpack -p --config webpack.production.js",
"build-dev": "cd ./private/static && webpack -p"
},



  • npm start のコマンドを実行すると Node.jswebpack-dev-server (内部はexpress) でWebアプリケーションが起動します。


  • http://localhost:4000/ にアクセスすると Welcome Home! のサンプルが表示されます。

node

view-source:

<html>

<head>
<meta charset="utf-8">
<title>Redux/React App</title>
<link href="./static/app.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div id="main"></div>

<script src="./static/bundle.js"></script>
</body>
</html>

これは Redux Generator が出力したサンプルで、Update Title をクリックして入力すると Welcome の隣の文字が変更されます。

redux-devtoolsreact-hot-loader など開発に便利なパッケージがバンドルされています。

まだ Node.js しか使っていないので、次は Rails も使います。



Rails controller



  • rails generate controller コマンドで ReactVirtual DOM を設置する場所を作ります。

$ rails generate controller main index



  • routes.rbRails のWebアプリケーション root を設定します。


config/routes.rb

Rails.application.routes.draw do

root 'main#index'
end



  • main_helper.rbDevelopment なら先ほどの Node.js のWebアプリケーションを参照するメソッドを準備します。


app/helpers/main_helper.rb

module MainHelper

def pack_path(path)
url = ""
url = "http://localhost:4000/static/" if Rails.env.development?
url + path
end
end



  • index.html.erbVirtual DOM が設置される id="main" を準備します。


  • app.cssbundle.jsMainHelperpack_path に設定します。


app/views/main/index.html.erb

<div id="main"></div>

<%= stylesheet_link_tag pack_path('app.css') %>
<%= javascript_include_tag pack_path('bundle.js') %>



  • webpack.config.jspublicPathMainHelper で指定した URL を追加します。


private/webpack/webpack.config.js

output: {

path: __dirname + '/static/',
publicPath: 'http://localhost:4000/static/',
filename: 'bundle.js',
hot: true
},


Development



  • RailsNode.js のWebアプリケーションを実行するのに foreman を利用します。


  • Gemfileforeman を追加します。

Gemfile:

$ echo "gem 'foreman', require: false" >> Gemfile



  • ProcfileRailsNode.js のWebアプリケーションの起動コマンドを追加します。

Procfile:

$ echo "web: rails server" >> Procfile

$ echo "pack: npm start" >> Procfile



  • bundle コマンドを Ruby のライブラリをインストールします。


  • foreman start コマンドでWebアプリケーションを起動します。

$ bundle

$ foreman start

http://localhost:3000/ にアクセスすると Redux のサンプルが表示されます。

development

StyleSheetJavaScripthttp://localhost:4000/ を参照しています。

view-source:

<div id="main"></div>

<link rel="stylesheet" media="screen" href="http://localhost:4000/static/app.css" />
<script src="http://localhost:4000/static/bundle.js"></script>

Rails が出力したわずかな ViewVirtual DOMView を足しているので

見た目や、性能は 4000 ポートの Node.js のWebアプリケーションと同じです。

もちろん redux-devtoolsreact-hot-loader が使えるので開発が捗ります。



Production

Production では redux-devtoolsreact-hot-loader は不要なので、webpack でまとめます。



  • Asset Precompileapp.cssbundle.js を追加します。


config/initializers/assets.rb

Rails.application.config.assets.precompile += %w(app.css bundle.js)




  • webpack.production.jsvendor/assets/ に出力されるように編集します。


private/static/webpack.production.js

output: {

path: __dirname + '../../../vendor/assets/',
publicPath: '/static/',
filename: 'javascripts/bundle.js',
},
plugins: [
new webpack.NoErrorsPlugin(),
devFlagPlugin,
new ExtractTextPlugin('stylesheets/app.css')
],



  • npm run build コマンドで app.cssbundle.js が生成されます。


  • rake assets:precompile コマンドを app.cssbundle.jsPrecompile します。


  • rails s -e production コマンドでWebアプリケーションを起動します。

$ echo /public/assets >> .gitignore

$ echo /vendor/assets >> .gitignore
$ npm run build
$ RAILS_ENV=production rake assets:precompile
$ RAILS_SERVE_STATIC_FILES=o SECRET_KEY_BASE=o rails s -e production

http://localhost:3000/ にアクセスすると Redux のサンプルが表示されます。

production

StyleSheetJavaScript/assets/ を参照しています。

view-source:

<div id="main"></div>

<link rel="stylesheet" media="screen" href="/assets/app-5edef2394b419bead200965dfdae792e54801bdd97f057758a8bc0a72f25685d.css" />
<script src="/assets/bundle-66f3247c874d05e4bf42eb08d4fc66d88bd796bdbca894259cd898078a39bf97.js"></script>

これで JavaScript on Node.js X Ruby on Rails の基本の準備ができました。

ViewReact に任せて RailsView にあまり関心を持たないほうがいいですね。



Tips

見た目が寂しなら Material-UIで簡単に装飾できます。

$ npm install material-ui --save



  • RaisedButton でボタンをいい感じに仕上げます。


private/static/js/components/Home.js

import React, {Component} from 'react';

import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import * as HomeActions from '../actions/HomeActions';
import styles from '../../css/app.css';
import RaisedButton from 'material-ui/lib/raised-button';

class Home extends Component {
render() {
const {title, dispatch} = this.props;
const actions = bindActionCreators(HomeActions, dispatch);
return (
<main>
<h1 className={styles.text}>Welcome {title}!</h1>
<RaisedButton label='Update Title' onClick={e => actions.changeTitle(prompt())} />
</main>
);
}
}

export default connect(state => state.Sample)(Home)


material-ui

JavaScript のライブラリの npmRuby のライブラリの Gem に作り替えて使う方法もよいですが

関心事を分離して開発することが幸せと感じます。

Enjoy JavaScript on Node.js X Ruby on Rails