【作業ログ】rails + mecab + natto で会話用DBを作る（１）

# はじめに
自動的に会話用の単語DBを作成する必要があったので、
rails + mecab (+ natto) 部分の作業メモ

# 環境
OS: Centos 6.5
gem |	version
Rails |	4.2.1

# 作業ログ
### 前準備
```
rails new talkdic
cd talkdic
git add .
git commit -m "create the project talkdb"
```

```rb:Gemfile
#gem "therubyracer', platforms: :ruby
```
のコメントを外しておく

```
bundle update
```

ここまでテンプレ

### モデルの準備
まずは用語を扱うためのTermモデルを作る

```
rails g model Term
```

```rb:db/migrate/xxxxxxxx_create_terms.rb
class CreateTerms < ActiveRecord::Migration
  def change
    create_table :terms do |t|
      t.string :partsOfSpeech ,null: false
      t.string :term ,null: false
      t.string :subType
      t.timestamps null: false
    end
  end
end
```

カラム名 | 用途
--:|:--
partsOfSpeech | 品詞
term | 語句
subType | この語句の用途の説明

```
rake db:migrate
```

###今後の方針を考える
とりあえずモデルを作ったので、どんなコントローラとビューを作って行こうかを今更考える。
#### 要件
* テキストボックスとボタンがあって、文章を入力すると、mecabが品詞に分解してくれる
* 特定の品詞だけtermデータベースにどんどん格納されていく
* 登録されたtermを一覧表示できるビューを用意する
 * term, partsOfSpeech, subtype, 採用/削除ボタンが並ぶ
 * 採用を押すと、この用語が有効であるフラグを立てる
 * 削除を押すと、この用語を削除する
 * subtype はドロップダウンで選択する

早速、モデルに足りないものが発覚。要件定義の前にモデルを作ったことを後悔

```
rails g migration add_accept_to_terms accept:integer
```

先ほど作ったモデルに accept フラグを準備。初期値を0にするように、以下のように編集

```rb:db/migrate/xxxxxxxx_add_accept_to_terms.rb
class AddAcceptToTerms < ActiveRecord::Migration
  def change
    add_column :terms, :accept, :integer,default: 0
  end
end
```

```
rake db:migrate
```

でマイグレーションを実行。
モデルが想定通りできているか確認する。

```
rails c
```

```rb:irb
2.1.1 :004 >   Term.new(partsOfSpeech: "名詞", term: "国家")
 => #<Term id: nil, partsOfSpeech: "名詞", term: "国家", subType: nil, created_at: nil, updated_at: nil, accept: 0> 
```

想定通りにモデルができている。良かった。
次に、何をするか。
1. 入力用のビューを作る
2. リスト表示用のビューを作る

リスト表示用のビューを作るのであれば、DBが空の状態だとやりにくいので、あらかじめDBにデータを適当に入れておきたい。
入力用のビューを作るのであれば、特にDBにデータを入れておく必要はない

なんとなくリストが見たいので、敢えて今回はリスト表示用のビューを作ることにする

### リスト表示ビュー作成
#### サンプルデータの投入

seeds.rb を編集

```rb:seeds.rb
100.times{
  Term.new(partsOfSpeech: ["名詞","動詞","形容詞"].sample,term: ["hoge","fuga","momo","urashima","natsu","umi","sabaku","yama","oka","kome"].sample<<"-"<<["taro","jiro","saburo","yama","kawa","ken","shi","fes"].sample).save
}
```

```
rake db:seed
```

でDBにサンプルデータを投入

```
rails c
```

で投入されたレコードを見てみる

```rb.irb
Term.all[1..10].each{|t| p t}
  Term Load (2.0ms)  SELECT "terms".* FROM "terms"
#<Term id: 2, partsOfSpeech: "名詞", term: "yama-yama", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 3, partsOfSpeech: "動詞", term: "natsu-yama", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 4, partsOfSpeech: "形容詞", term: "oka-yama", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 5, partsOfSpeech: "形容詞", term: "fuga-shi", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 6, partsOfSpeech: "動詞", term: "urashima-kawa", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 7, partsOfSpeech: "名詞", term: "kome-ken", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 8, partsOfSpeech: "動詞", term: "momo-ken", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 9, partsOfSpeech: "動詞", term: "natsu-shi", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 10, partsOfSpeech: "形容詞", term: "natsu-jiro", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
#<Term id: 11, partsOfSpeech: "動詞", term: "sabaku-saburo", subType: nil, created_at: "2015-07-25 08:29:30", updated_at: "2015-07-25 08:29:30", accept: 0>
```

ちゃんとデータができていることを確認

#### ビュー/コントローラの作成
コントローラ名は複数形。モデルは単数形。コントローラ名は単数でも良いけど、複数にしておいた方が後々。

```
rails g controller terms
```

まずはindexアクションを作る

```rb:app/controllers/terms_controller.rb
class TermsController < ApplicationController
  def index
    @terms = Term.all
  end
end
```

Term.allだと全部取ってきてしまうので、後で変えなければいけないんだけど、とりあえずはallにしておく

次は、ビューを。indexメソッドに、renderとか書かなかったので、自動的に、index.html.erbが参照されるので、作成する

```rb:app/views/terms/index.html.erb
<h1>terms</h1>
<div>
  <table>
    <tr>
      <th>品詞</th><th>単語</th>
    </tr>
    <% @terms.each do |x| %>
    <tr>
      <td><%= x.partsOfSpeech %></td>
      <td><%= x.term %></td>
    </tr>
  <% end %>
  </table>
</div>
```

まだ最低限。
とりあえず、ここまでで画面が見たいので、ルーティングを設定してみる

```rb:config/routes.rb
Rails.application.routes.draw do
  root "terms#index"
  resources :terms
end
```

確認

```bash:shell
$ rake routes
   Prefix Verb   URI Pattern               Controller#Action
     root GET    /                         terms#index
    terms GET    /terms(.:format)          terms#index
          POST   /terms(.:format)          terms#create
 new_term GET    /terms/new(.:format)      terms#new
edit_term GET    /terms/:id/edit(.:format) terms#edit
     term GET    /terms/:id(.:format)      terms#show
          PATCH  /terms/:id(.:format)      terms#update
          PUT    /terms/:id(.:format)      terms#update
          DELETE /terms/:id(.:format)      terms#destroy
```
余分なルーティングも設定されてしまっているけど、無視する。
と思ったけど、ちゃんとonlyを付けよう

```rb:config/routes.rb
Rails.application.routes.draw do
  root "terms#index"
  resources :terms, :only => [:index]
end
```

```bash:shell
$ rake routes
Prefix Verb URI Pattern      Controller#Action
  root GET  /                terms#index
 terms GET  /terms(.:format) terms#index
```

いよいよサーバを起動

```bash:shell
$ rails s -b 0.0.0.0 -p 4000
```

hogehoge.com:4000/
にアクセスしてみる。アクセスできなかったら、iptablesでTCPポート4000にアクセスできる設定かどうか確認する
***
![index.html.PNG](https://qiita-image-store.s3.amazonaws.com/0/86918/5508a10e-38b8-a3e2-db85-d4dc0f017706.png)
***
こんな感じで表示されているはず

### mecab + natto を用意する
タイトル詐欺になりそうなので、ここでmecab + natto をインストールしておく
まずはmecabをインストールする。

```
$ sudo rpm -ih http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm
$ sudo yum makecache
$ sudo yum -y install mecab mecab-ipadic
```

インストール確認

```
$ echo "今日の天気はファンタジック" | mecab
今日    名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
の      助詞,連体化,*,*,*,*,の,ノ,ノ
天気    名詞,一般,*,*,*,*,天気,テンキ,テンキ
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
ファンタジック  名詞,固有名詞,組織,*,*,*,*
EOS
```

インストール確認終了。つぎはnatto

Gemfileに

```
gem 'natto'
```

を追加して

```
bundle install
```

する。libmecab.soのパスをMECAB_PATHに追加する必要がある

```
echo "export MECAB_PATH=/usr/lib64/libmecab.so.2" >> ~/.bash_profile
```

動作確認

```
rails c
```

```rb:irb
> text = "ノスタルジックな教会に今日も花を配達する"
> nt = Natto::MeCab.new
> nt.parse(text){|w| puts w.surface << "\t" <<  w.feature}
ノスタルジック  名詞,一般,*,*,*,*,*
な      助動詞,*,*,*,特殊・ダ,体言接続,だ,ナ,ナ
教会    名詞,一般,*,*,*,*,教会,キョウカイ,キョーカイ
に      助詞,格助詞,一般,*,*,*,に,ニ,ニ
今日    名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
も      助詞,係助詞,*,*,*,*,も,モ,モ
花      名詞,一般,*,*,*,*,花,ハナ,ハナ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
配達    名詞,サ変接続,*,*,*,*,配達,ハイタツ,ハイタツ
する    動詞,自立,*,*,サ変・スル,基本形,する,スル,スル
        BOS/EOS,*,*,*,*,*,*,*,*
=> nil
```

正常に動いていることを確認

### indexを要件通りに作成する
先ほどはindexをとりあえず作ったので、ちゃんと要件通りに作成することにする。
実現できていない要件
- subtypeのドロップダウンリストが表示されていない
- 採用、削除ボタンが表示されていない
- 採用されたレコードを非表示にしていない

まず、採用されたレコードを非表示にするのが簡単なので、この作業を行う。viewに渡しているtermリストから、採用済みのレコードを除けばよいので

```rb:app/controllers/terms_controller.rb
class TermsController < ApplicationController
        def index
                @terms = Term.where(accept:0)
        end
end
```

として、whereで条件を指定する

次にsubtypeのドロップダウンリストを表示する
subtypeはドロップダウンリストにする必要があるので、レコードにべた書きされているのは良くない。ということで、subtypeモデルを作って、サブタイプはsubtype_idで管理することにする。さらに、subtypeはラベル的に使える方が便利な気がしたのでそこらへんも変更する。