facebook製html(wysiwyg)エディタ draft-jsをrailsで利用してみる

[もう少ししっくりする方法を記事にしました。](http://qiita.com/iwsksky/items/0f60b76dad1cce4566cd)

管理画面のようなものを作るとき、しばしば利用されるwysiwygエディタ（htmlタグを埋め込めるエディタ）。
railsで利用しようと思ったとき手軽に入れられるのはgem対応しているckeditor等ですが、さすが見た目がダサすぎるしフロントエンドのテクノロジーもだいぶ進化を遂げているということでreactで動くfacebook製エディタdraft-jsを利用してみました。
[draft-js](https://facebook.github.io/draft-js/)
##動作環境
rails ５系 or ４系
####gem
react-rails
browserify-rails
####npm
react@15.4.1
react-dom@15.4.1
draft-js@0.9.1
browserify@13.1.1
browserify-incremental@3.1.1

##どこまでフロントをレールに乗せるか
近年はrailsのレールからフロントエンドの技術をあえて外していく流れがあるようで、sprocketがショボいとかパッケージ管理はnpmよりbowerがいいとか色々な話があったのですが、とにかく今回は簡単にdraft-jsを導入しようということでnpmでnode系パッケージを管理するにとどまっています。react-railsとbrowserify-railsを利用しているためgemとnpmに跨ったライブラリ管理になっているのは違和感ではあるんですけど。


##手順
手順は非常に単純です。
1.パッケージのインストール
2.assets系の設定
3.draft-js導入

###1.パッケージのインストール
それぞれgemとnpmで入れるものがあるので進めていきましょう。
少し複雑なんですがreact_componentを利用するためにreact-railsをgemでインストールし、react本体はnpmでインストールします。
browserify-railsについても同様でbrowserify本体はnpmからインストールします。
 
```Gemfile.
gem 'react-rails'
gem 'browserify-rails'
```
bundle install（インストール場所はお好きにどうぞ）とreact-railsの初期化

```bash
$ bundle install --path=vendor/bundle
$ rails g react:install
```
npmはコマンドラインからrailsでインストールしましょう。

```bash
$ npm install browserify browserify-incremental react react-dom reactify --save
```

###2.assets系の設定
draft-jsを定義するReactComponentを作成

```bash
$ rails g react:component Draft
```

application.rbとapplication.jsにそれぞれ設定を書き込んでいきます。
application.rbにはnpmの読み込みとbrowserifyのoptionを設定します。

```application.rb
class Application < Rails::Application
  #略
  config.assets.paths << Rails.root.join('node_modules')
  config.browserify_rails.commandline_options = "--t babelify"
  #略
end
```

application.jsにはassetsの読み込み設定を書き込みます。
おそらく```require react ```や```require react-dom```といった記述があるかと思いますが、今回はnpmからreactを利用するので削除します。components.jsの読み込みは規約となっておりreact_componentの読み込みはこちらで行います。またcomponent自体はcomponentsディレクトリに保存していきます。

```application.js
//= require jquery
//= require jquery_ujs
//= require components
//
```


```components.js
//= require_self
//= require react_ujs

window.React = require('react');
window.ReactDOM = require('react-dom');
window.Draft = require('./components/draft.js.jsx');
```

###3.draft-js導入
2で定義しているdraft.js.jsxにdraft-jsを実装していくわけですが、今回は[この辺](https://github.com/facebook/draft-js/tree/master/examples/draft-0-9-1/rich)を参考にしてコピペしました。コピペなのでコードは省略します、ご了承ください。

```draft.js.jsx
const {Editor, EditorState, RichUtils} = Draft;

      class RichEditorExample extends React.Component {
        constructor(props) {
          super(props);
          this.state = {editorState: EditorState.createEmpty()};

          this.focus = () => this.refs.editor.focus();
          this.onChange = (editorState) => this.setState({editorState});

          this.handleKeyCommand = (command) => this._handleKeyCommand(command);
          this.onTab = (e) => this._onTab(e);
          this.toggleBlockType = (type) => this._toggleBlockType(type);
          this.toggleInlineStyle = (style) => this._toggleInlineStyle(style);
        }

     /*------略-------*/
```

このままだと見た目がダサいのでcssのほうも公式から頂戴しましょう、assets/stylesheets/application.scssと並列にcssを配置します。

最後に作成したcomponentをviewで読み込みます。今回はroot設定とかは省略しますがご了承ください。

```index.html.erb
<%= react_component('Draft') %>
```


結果はこちら
![image](https://qiita-image-store.s3.amazonaws.com/0/56262/e3dd65ab-cfaf-662c-c418-0d8ba5cb2f89.png)
美しいです！

##所感
フロントの技術は正直いろいろ有りすぎて戸惑いましたがサーバー側の人間も今後向き合っていかないといけないものだなと感じました。Reactとか完全に裏側の人がやるための設計ですしね。
それにしてもReactとwysiwygエディタは相性が良さそうだしいくらでも便利なのがあると思ったんですが、なかなかコレと即決できるものがなく、フロントの技術は今まさに発展しているものなのだとしみじみ感じました。

draft-js用のpluginだと下記ページ充実しているのでよければご覧ください。
https://www.draft-js-plugins.com/