Rails のデータを React から参照するアプリケーション作成 ( Rails + React + MySQL )

# はじめに
他の方の記事を参考に自分なりに Rails + React + MySQL の環境を作ってみたので、その時のやり方をまとめました。
上からコピペするだけで動くようにまとめてみたので、はじめてだけどやってみたいという方がいらっしゃれば、試していただきたいです。

# コマンド

こちらの項目で実施することは以下となります。
上から順番にターミナルで実行していただければと思います。

* やること
    * rails アプリケーションの作成
    * webpacker インストール
    * react インストール
    * MVC作成
    * migration

```
$ rails _5.2.4.2_ new react_sample_app --webpack=react -d mysql

$ cd react_sample_app

# Webpackを有効にする
$ rails webpacker:install

# Reactを有効にする
$ rails webpacker:install:react

# sample モデルを scaffold にて作成
$ rails g scaffold sample title:string body:string

# migrate
$ rails db:create
$ rails db:migrate
```

※routeなどの細かい設定が面倒だと思ってscaffoldを使いましたが、scaffoldが必須というわけではありません。


# View
続いては、Viewの設定をしていきます。
## application.html.erb
全体へ反映させたいことをこちらに記載していきます。

* やること
    * ```javascript_include_tag``` → ```javascript_pack_tag``` へ変更する
    * view のファイル毎に読み込む javascript(React) を指定するために、```<%= yield :javascript %>```を追記

```erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>ReactSampleApp</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

    <!-- javascript_include_tag を下記へ変更する -->
    <!-- javascript_include_tag 'application', 'data-turbolinks-track': 'reload' -->
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>

    <!-- view のファイル毎に読み込む javascript(React) を指定するために必要 -->
    <%= yield :javascript %>
  </body>
</html>
```


## 個別のerbファイル

ここでは例えとして、```app/views/samples/index.html.erb```上に変更を加えますが、他の画面で実装していただいも何も問題ありません。

* やること
    * Rails から React へ渡すデータを作成（content_tagにより）
    * view のファイル毎に読み込む javascript(React) を指定する

```erb:app/views/samples/index.html.erb
<!-- 省略 -->
<!-- 一番下の行に以下を追記 -->

<!-- content_tag の data 属性を React へ渡す -->
<%= content_tag :div,
                id: "resources-container",
                data: {
                    q: params,
                    resources_path: samples_path,
                }.to_json do %>
<% end %>

<!-- view のファイル毎に読み込む javascript(React) を指定することができる -->
<% content_for :javascript do %>
  <%= javascript_pack_tag 'hello_react' %>
<% end %>

```

# javascript

ここでは、コマンド入力時に作成した```app/javascript/packs/hello_react.jsx```を用いますが、個々にファイルを設定していただいて問題ありません。

* やること
    * Hello コンポーネントの作成
        * props を state に格納する
        * state.name を更新する関数を作成する
        * レンダリングする HTML要素を作成する
    * Rails から読み込みたい & React からレンダリングしたい要素を指定
    * 指定した要素(node)から、data を取得する
    * Hello コンポーネントを呼び出し
        * data を Hello コンポーネントの props として渡す 
        * node へ React からレンダリングする

```jsx:app/javascript/packs/hello_react.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

// Hello コンポーネントの作成
class Hello extends React.Component {

  constructor(props) {
    super(props)

    // props を state に格納する
    this.state = {
      q: this.props.q || '',
      resources_path: this.props.resources_path || '',
      name: this.props.name || 'David'
    }
  }

  render() {
    // state.name を更新する関数を作成する
    const setName = e => {
      this.setState({
        name: e.target.value
      })
    }

    // レンダリングする HTML要素を作成する
    return (
        <div>
          <div>Hello {this.state.name}!</div>
          <input type="text" defaultValue={this.state.name} onChange={setName}/>
        </div>
    )
  }
}

document.addEventListener('DOMContentLoaded', () => {
  // Rails から読み込みたい & React からレンダリングしたい要素を指定する
  const node = document.getElementById('resources-container')
  // 指定した要素(node)から、data を取得する
  const data = JSON.parse(node.getAttribute('data'))

  ReactDOM.render(
    // Hello コンポーネントを呼び出し
    // Rails から取得した data を Hello コンポーネントの props として渡す 
    <Hello {...data}/>,
    // node へ React からレンダリングする
    node
  )
})
```

# rails s と webpacker 起動を一括して実行する方法

以下に、```scripts```の部分を追記します。
すると、```yarn start```をターミナル上で実行するたけで、```rails s & bin/webpack-dev-server```を実行してくれます。

```json:package.json
{
  "name": "react_sample_app",
  "private": true,
  "dependencies": {
    "@babel/preset-react": "^7.10.1",
    "@rails/webpacker": "5.1.1",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "prop-types": "^15.7.2",
    "react": "^16.13.1",
    "react-dom": "^16.13.1"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.11.0"
  },

  // 以下を追記する
  "scripts": {
    "start": "rails s & bin/webpack-dev-server"
  }
}

```

```
$ yarn start
```

# まとめ
いかがでしたか。
間違いなどがあれば、お手数をおかけしますがご指摘いただけると嬉しいです。

React を理解しているとスマホアプリを作れる React Native への導線が引けるかなーと思い勉強中です。
まずは、Rails と連携していけているアプリケーションを作れるようになりたいなーと思っています。

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/