13
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ruby on RailsAdvent Calendar 2015

Day 25

Node.js X Rails Engine

Last updated at Posted at 2015-12-24

8日目 に続けての投稿です。
今回は React and ReduxRails Engine でクロスさせる開発を紹介します。

Rails Engine は Rails に Webアプリケーションの部品として機能を追加できる仕組みです。
React and Redux もコンポーネントを組合せて機能を作ります。

  • Rails Engine: Web Application Component Framework
  • React and Redux: Web Client Component Framework

React and Redux の コンポーネント を Rails Engine でさらに コンポーネント にする仕組みだと
関心事の分離して設計できて コンポーネント指向 が捗ります。

サンプルはこちらです。

Environment

  • Ruby: v2.2.3
  • Rails: v4.2.5
  • React: v0.14.0
  • Redux: v3.0.4

Rails

まずは、Rails に Virtual DOM をレンダリングするためのサーバーサイドを構築します。

Setup

  • rails plugin new のコマンドで Rails Engine を作成します。
  • --mountable のオプションで Rails の部品として開発できます。
  • foreman は後で Node.js と Rails を起動するのに利用します。
rails plugin new rails_engine_react_example --mountable \
  --skip-javascript \
  --skip-bundle
$ cd rails_engine_react_example/
$ echo "gem 'foreman', require: false" >> Gemfile
$ bundle

Making

  • engine.rbgenerate コマンドのデフォルトを記述します。
lib/rails_engine_react_example/engine.rb
module RailsEngineReactExample
  class Engine < ::Rails::Engine
    isolate_namespace RailsEngineReactExample

    config.generators do |g|
      g.javascripts false
      g.stylesheets false
      g.helper false
    end
  end
end
  • rails generate controller コマンドで controllerview を作ります。
$ rails generate controller main index
  • routes.rbmain_controllerroot に設定します。
  • *path は Tips の Redux Router で利用しています。
config/routes.rb
RailsEngineReactExample::Engine.routes.draw do
  root 'main#index'
  get '*path', to: 'main#index'
end
  • index.html.erb に Virtual DOM がレンダリングされる id="main" を記述します。
app/views/rails_engine_react_example/main/index.html.erb
<div id="main"></div>
  • application_helper.rbstylesheetjavascript の参照先を切替えるメソッドを追加します。
app/helpers/rails_engine_react_example/application_helper.rb
module RailsEngineReactExample
  module ApplicationHelper
    def switch_stylesheet_link_tag(path)
      path = "http://localhost:4000/assets/stylesheets/#{path}.css" if ENV["DEBUG"]
      stylesheet_link_tag(path)
    end

    def switch_javascript_include_tag(path)
      path = "http://localhost:4000/assets/javascripts/#{path}.js" if ENV["DEBUG"]
      javascript_include_tag(path)
    end
  end
end
  • application.html.erb に先ほどのヘルパーのメソッドを記述します。
app/views/layouts/rails_engine_react_example/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>RailsEngineReactExample</title>
  <%= switch_stylesheet_link_tag "rails_engine_react_example/application" %>
  <%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
  <%= switch_javascript_include_tag "rails_engine_react_example/application" %>
</body>
</html>

Run

  • rails server コマンドで起動して http://localhost:3000/rails_engine_react_example にアクセスします。

engine

真っ白ですね... 安心してください、 Virtual DOM はこれからです。

Node.js

次は、Node.js で Virtual DOM をレンダリングするためのフロントエンドを構築します。

Setup

  • Node.js は /private/static に設置します。
  • yo redux のコマンドで React and Redux が構築できます。
    • Node.js は 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
  • jsapp にリネームします。(csscomponents で記述する流れですね。)
  • package.json ファイルはルートディレクトリにコピーします。
$ mv js app
$ 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"
},
  • webpack.config.js を Rails のヘルパーのメソッドで参照できるように調整します。
private/static/webpack.config.js
entry: [
  'webpack-dev-server/client?http://localhost:4000',
  'webpack/hot/only-dev-server',
  './app/index.js'
],
output: {
  path: __dirname + '/assets/',
  publicPath: 'http://localhost:4000/assets/',
  filename: 'javascripts/rails_engine_react_example/application.js',
  hot: true
},
plugins: [
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoErrorsPlugin(),
  devFlagPlugin,
  new ExtractTextPlugin('stylesheets/rails_engine_react_example/application.css')
],
  • webpack.production.js を Rails の app/assets/ に出力するように調整します。
private/static/webpack.production.js
entry: [
  './app/index.js'
],
output: {
  path: __dirname + '../../../app/assets/',
  publicPath: '/static/',
  filename: 'javascripts/rails_engine_react_example/application.js',
},
plugins: [
  new webpack.NoErrorsPlugin(),
  devFlagPlugin,
  new ExtractTextPlugin('stylesheets/rails_engine_react_example/application.css')
],

Run

  • Rails Engine は Rails にマウントしている状態の dummy が提供されています。
  • foreman の Procfile に Rails と Node.js の起動コマンドを追加します。
  • DEBUG=true foreman start コマンドで起動します。
$ cd test/dummy/
$ echo "web: rails server" >> Procfile
$ echo "pack: npm start" >> Procfile
$ DEBUG=true foreman start

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

development

  • npm run build コマンドで application.jsapplication.css が生成されます。
  • rails server コマンドで起動します。
$ npm run build
$ rails server

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

production

これで Node.js X Rails Engine の基本の準備ができました。
ViewReact に任せて RailsView にあまり関心を持たないほうがいいですね。

Tips

Redux Router

RailsRouter もあまり関心を持たないほうが...

Setup

  • react-routerredux-simple-router を利用します。
$ npm install react-router --save
$ npm install redux-simple-router --save

Making

コードは一部ですが Router や Link を記述します。

  • App.js に Router を記述します。
private/static/app/containers/App.js
<Router history={history}>
  <Route path="/" component={Home}>
    <Route path="parent" component={Parent}>
      <Route path="child" component={Child} />
      <Route path="child/:id" component={Child} />
    </Route>
  </Route>
</Router>
  • Home.js に Link を記述します。
private/static/app/components/Home.js
<dev>
  <ul>
    <li><Link to="/">Home</Link></li>
    <li><Link to="/parent">parent</Link></li>
    <li><Link to="/parent/child">child</Link></li>
    <li><Link to="/parent/child/1">child 1</Link></li>
    <li><Link to="/parent/child/2">child 2</Link></li>
    <li><Link to="/parent/child/3">child 3</Link></li>
  </ul>
</dev>

Run

Link のエリアをクリックとサーバーサイドにはリクエストが送信されませんが、レンダリングされます。
URLを入力するとサーバーサイドにはリクエストが送信されますが、Rails に *path を設定しているので Virtual DOM がレンダリングされます。

redux-router

Redux は状態を管理するメカニズムがあります。ページ遷移も状態として管理されます。
RailsMVC2 ですが、 View に状態が管理されるので MVC ですね。

Enjoy Node.js X Rails Engine

13
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?