Rails4系でごく単純な　1対多の実装を行う（ミステイク版）

フレームワークというものは、芋づる式に設定がでてくるものだ・・・


# やりたいこと


- 表示させたい対象が存在する
- 対象には、その内容を説明するタグが０〜複数存在する
- 対象の作成、編集画面で編集できる

# 実現方法

ものすごく簡略化

- とりあえず、対象１に対しタグが多数存在するモデル構造
- タグ名は直接記入する
- とりあえず今は、対象１つに対して、最大５個のタグをつけられること

# 実装の前に

## 環境

- Rails 4.2.5 (Bundle Installしたもの）
- ruby 2.2.3 （rbenv で選択中）

## 注意事項

- タグをつける対象のモデルは page という名前であり、すでに作成されています。
- bundle exec rails ~ とかありますが、このRailsプロジェクト用に用意したgem使っているという意味です。例によって環境

# 実装開始

## まずはタグ用のモデルを用意する

```bash:terminal
$ bundle exec rails g model extag page:references label:string
```

ここでは、page:references というところに注目。
参照用の設定記述が作成されます。

### マイグレーションファイルはこんな感じに

```ruby:migrate
class CreateExtags < ActiveRecord::Migration
  def change
    create_table :extags do |t|
      t.references :page, index: true, foreign_key: true
      t.string :label

      t.timestamps null: false
    end
  end
end
```

t.references :page, index: true, foreign_key: true

とか、ちょっと見慣れない記述が出てきました。

## マイグレーションを実施し、タグ用テーブルを生成すると・・・

データベースを更新します。

```bash:terminal
$ bundle exec rake db:migrate
```

とかやると

```bash:terminal
|id|page_id|label|created_at|updated_at|
```
とかいうカラムを持ったテーブルが作成されます。

日付部分の説明は省略しますが

- id 　　　　　このテーブル内のデータに割りふられる固有のID
- page_id 　　関連するモデルpageの項目に紐づく
- label　　　 タグの名前

といった内容。注目すべきはpage_id 

```bash:terminal
|id|page_id|label|created_at|updated_at|
|1 |      3|hoge | （省略）   | （省略）  |
```

みたいな場合、モデルpageのid=3に保存されているレコードに　タグ名"hoge" が
関連付けられていることになります。

## モデルの改修

### page（１対多の１の方）

下記のように記述を追加します。
追記：
```ruby:page.rb
class Page < ActiveRecord::Base

	# extagと１対多な関連付けが存在する
	has_many :extags, dependent: :destroy
	# page が extag を内包する　という意味？
	accepts_nested_attributes_for :extags, allow_destroy: true
end
```

accepts_nested_attributes_for　に関しては
pageと関連し　ettag（タグ）を操作する。というの意味合い。

検索するか、ここでも参考に
http://blog.livedoor.jp/sasata299/archives/51931176.html


### extag （１対多の多の方）

rails generate が空気・・・いや命令を読んで、 belongs_to page
（このモデルは pageモデルに所属する（多対１の関連になる）と最初から記述しています。

```
class Extag < ActiveRecord::Base
  belongs_to :page
end

```

## コントローラの改修

修正が必要になるところだけ抜粋。
具体的にはnew（新規にデータを作成）とpage_params（StrongParameter：DBに書き込む前などのチェック）に修正を加える。　


### まずはnewの方から

```ruby:pages_controller.rb
  # GET /pages/new
  def new
    @page = Page.new
   #追記　５つ分だけ関連付けが用意される。
    5.times{
      @page.extags.build
    }
  end
```

まんま、５つ分だけextagの要素が作成されます。

### 続いて、params（ StrongParameter ) の箇所を修正

```ruby:pages_controller.rb
# Never trust parameters from the scary internet, only allow the white list through.
    def page_params
     #extagsのlabel項目も許可するようにする
     #params.require(:page).permit(:name, :view, :desc)
      params.require(:page).permit(:name, :view, :desc, extags_attributes: [:label])
    end

```

ここでの記述は
(belong_toするほうのモデル）_attributes: [:(項目１）,:（項目２）・・・]
ということになる。


## ビューの改修（正確には　_formの部分だけど）

今回は編集処理をするときのフォームを改修する。
なお、関係あるところだけ抜粋します。

```rails:_form.html.erb
（前略）
  <div class="field">
    <%= f.label :desc %><br>
    <%= f.text_field :desc %>
  </div>
  <div class="field">
    <%= f.label :extags , "直接タグ名（最大５個）" %><br>
      <%= f.fields_for :extags do |et| %>
        <%= et.text_field :label %>
      <% end %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
（以下略）
```

単に、fileds_for でテキストタイプのフォームを生成しています。

Railsドキュメントによる説明はこちら
http://railsdoc.com/references/fields_for

＃ （追加）参考
20141208
Railsでaccepts_nested_attributes_forとfields_forを使ってhas_many関連の子レコードを作成/更新するフォームを作成

http://ruby-rails.hatenadiary.com/entry/20141208/1418018874

# 実行してみる（ミステイク含む）

新規登録時のサンプルは下記のようになります。

```bash:terminal

Started POST "/pages" for ::1 at 2016-01-03 20:38:02 +0900
Processing by PagesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"JPRV6GWmAp6Qz4MwLA4fQK1JKKwauWCkha+UUEixvAD1nfOcdKTojxjSE2sET3qX1+inc6SC54TZftuCwW3/cg==", "page"=>{"name"=>"b", "view"=>"1", "desc"=>"hoge", "extags_attributes"=>{"0"=>{"label"=>"タグ１"}, "1"=>{"label"=>"タグ２"}, "2"=>{"label"=>""}, "3"=>{"label"=>""}, "4"=>{"label"=>""}}}, "commit"=>"Create Page"}
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "pages" ("name", "view", "desc", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["name", "b"], ["view", 1], ["desc", "hoge"], ["created_at", "2016-01-03 11:38:02.794453"], ["updated_at", "2016-01-03 11:38:02.794453"]]
  SQL (0.2ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", "タグ１"], ["page_id", 2], ["created_at", "2016-01-03 11:38:02.800693"], ["updated_at", "2016-01-03 11:38:02.800693"]]
  SQL (0.1ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", "タグ２"], ["page_id", 2], ["created_at", "2016-01-03 11:38:02.802259"], ["updated_at", "2016-01-03 11:38:02.802259"]]
  SQL (0.1ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", ""], ["page_id", 2], ["created_at", "2016-01-03 11:38:02.803250"], ["updated_at", "2016-01-03 11:38:02.803250"]]
  SQL (0.1ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", ""], ["page_id", 2], ["created_at", "2016-01-03 11:38:02.804747"], ["updated_at", "2016-01-03 11:38:02.804747"]]
  SQL (0.1ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", ""], ["page_id", 2], ["created_at", "2016-01-03 11:38:02.807215"], ["updated_at", "2016-01-03 11:38:02.807215"]]
   (2.5ms)  commit transaction
Redirected to http://localhost:3000/pages/2
Completed 302 Found in 22ms (ActiveRecord: 3.6ms)

```

表示はこんな感じ

```bash:terminal
Started GET "/pages/2" for ::1 at 2016-01-03 20:38:02 +0900
Processing by PagesController#show as HTML
  Parameters: {"id"=>"2"}
  Page Load (0.2ms)  SELECT  "pages".* FROM "pages" WHERE "pages"."id" = ? LIMIT 1  [["id", 2]]
  Rendered pages/show.html.erb within layouts/application (1.5ms)
Completed 200 OK in 122ms (Views: 98.9ms | ActiveRecord: 0.2ms)


Started GET "/pages/2/edit" for ::1 at 2016-01-03 20:39:36 +0900
Processing by PagesController#edit as HTML
  Parameters: {"id"=>"2"}
  Page Load (2.1ms)  SELECT  "pages".* FROM "pages" WHERE "pages"."id" = ? LIMIT 1  [["id", 2]]
  CACHE (0.0ms)  SELECT  "pages".* FROM "pages" WHERE "pages"."id" = ? LIMIT 1  [["id", "2"]]
  Extag Load (0.2ms)  SELECT "extags".* FROM "extags" WHERE "extags"."page_id" = ?  [["page_id", 2]]
  Rendered pages/_form.html.erb (8.5ms)
  Rendered pages/edit.html.erb within layouts/application (13.7ms)
Completed 200 OK in 81ms (Views: 77.7ms | ActiveRecord: 2.3ms)


Started PATCH "/pages/2" for ::1 at 2016-01-03 20:39:57 +0900
Processing by PagesController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"RL6B3FoPk8RZnc1cjdpD82+UvGadjkQkaay2P8FTQgeV1yeoSw151dGAXQelmyYkFTUzuSO1wwQ1ffntSI8BdQ==", "page"=>{"name"=>"b", "view"=>"1", "desc"=>"hoge", "extags_attributes"=>{"0"=>{"label"=>"タグ１", "id"=>"16"}, "1"=>{"label"=>"タグ２2", "id"=>"17"}, "2"=>{"label"=>"", "id"=>"18"}, "3"=>{"label"=>"", "id"=>"19"}, "4"=>{"label"=>"", "id"=>"20"}}}, "commit"=>"Update Page", "id"=>"2"}
  Page Load (2.1ms)  SELECT  "pages".* FROM "pages" WHERE "pages"."id" = ? LIMIT 1  [["id", 2]]
Unpermitted parameter: id
Unpermitted parameter: id
Unpermitted parameter: id
Unpermitted parameter: id
Unpermitted parameter: id
   (0.1ms)  begin transaction
  SQL (2.6ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", "タグ１"], ["page_id", 2], ["created_at", "2016-01-03 11:39:57.506513"], ["updated_at", "2016-01-03 11:39:57.506513"]]
  SQL (0.1ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", "タグ２2"], ["page_id", 2], ["created_at", "2016-01-03 11:39:57.510465"], ["updated_at", "2016-01-03 11:39:57.510465"]]
  SQL (0.1ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", ""], ["page_id", 2], ["created_at", "2016-01-03 11:39:57.512108"], ["updated_at", "2016-01-03 11:39:57.512108"]]
  SQL (0.1ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", ""], ["page_id", 2], ["created_at", "2016-01-03 11:39:57.514146"], ["updated_at", "2016-01-03 11:39:57.514146"]]
  SQL (0.1ms)  INSERT INTO "extags" ("label", "page_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["label", ""], ["page_id", 2], ["created_at", "2016-01-03 11:39:57.515796"], ["updated_at", "2016-01-03 11:39:57.515796"]]
   (2.3ms)  commit transaction
Redirected to http://localhost:3000/pages/2
Completed 302 Found in 22ms (ActiveRecord: 7.4ms)


Started GET "/pages/2" for ::1 at 2016-01-03 20:39:57 +0900
Processing by PagesController#show as HTML
  Parameters: {"id"=>"2"}
  Page Load (1.3ms)  SELECT  "pages".* FROM "pages" WHERE "pages"."id" = ? LIMIT 1  [["id", 2]]
  Rendered pages/show.html.erb within layouts/application (0.6ms)
Completed 200 OK in 79ms (Views: 76.1ms | ActiveRecord: 1.3ms)


```

あれ？　なんでinsert