【Ruby on Rails】collection_check_boxes で 詰まったから...

## はじめに
Rails 4.0.2以降から使用できる
ViewHelper の `collection_check_boxes` を使用しようとして少し詰まったので、
簡単なアプリケーションを作成してみて、楽しく覚えてみた。


## 環境
- Ruby: 2.4.0
- RoR: 5.0.6
- haml



## やりたいこと

#### User を 作成するときに 飲み物(Drink)を 選択して create できる。
プラスα - 選択肢にない飲み物(Drink)が 出てきたら 飲み物も新規登録できるように。


![2018-01-24 17.14.15.png](https://qiita-image-store.s3.amazonaws.com/0/158112/a36160a9-9883-5548-3611-b86f1dccb6b6.png)


いわゆる、

**パシリの為の パシリによるアプリケーション**

```

- タケシは、 コーラ。
- サトルは、コーヒーと水。
- ハナコは、お茶。

あれ、、、全部覚えてられないな。。。orz

```



# やってみた

scaffold で User, Drink, DrinkUser を 作成
多 対 多 の関係性を 記していく。


## Model

```user.rb

class User < ApplicationRecord

  has_many :drink_users
  has_many :drinks, through: :drink_users
  accepts_nested_attributes_for :drink_users, allow_destroy: true


end

```

```drink.rb

class Drink < ApplicationRecord

  has_many :drink_users
  has_many :users, through: :drink_users

end


```

```drink_user.rb

class DrinkUser < ApplicationRecord

  belongs_to :user, optional: true
  belongs_to :drink, optional: true

end


```

## Controller

users の new に Drink を 用意しておく

```users_controller.rb
class UsersController < ApplicationController

  def new
    @user = User.new
    @drinks = Drink.all
  end

... ... ... ...

  private

  def user_params
    params.require(:user).permit(:name, drink_ids: [])
  end

end

```

scaffold で 作成された Controllerに
`@drinks = Drink.all` (チェックボックスの選択に使用)と
StrongParametersに `drink_ids: []` (配列のパラメーターを許可) を足した。


## View

```users/_from.haml

= form_for(user) do |f|
  - if user.errors.any?
    #error_explanation
      %h2
        = pluralize(user.errors.count, "error")
        prohibited this user from being saved:
      %ul
        - user.errors.full_messages.each do |message|
          %li= message
  .field
    = f.label :name
    = f.text_field :name

    = f.collection_check_boxes :drink_ids, @drinks, :id, :name, include_hidden: false do |b|
      = b.label { b.check_box + b.text }

  .actions
    = f.submit


```

`= f.collection_check_boxes` の チェックボックスの記述を追加。


## Seed

```db/seeds.rb

%W[コーヒ コーラ お茶 紅茶 ミルクティ 水].each { |a| Drink.create(name: a) }

```
よく お頼みになる飲み物を seedファイルで予め用意しておく。
`rails db:seed` の実行を忘れずに。

```drinks_tables.
+----+--------------------+---------------------+---------------------+
| id | name               | created_at          | updated_at          |
+----+--------------------+---------------------+---------------------+
|  1 | コーヒ               | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  2 | コーラ               | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  3 | お茶                | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  4 | 紅茶                | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  5 | ミルクティ            | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  6 | 水                 | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
+----+--------------------+---------------------+---------------------+
```

<br>
-----------------------


これだけで
`/users/new`に アクセスすると、
人の名前を入力して、飲みモノを 選んで, データを作成することができる。


<br>
<br>


# collection_check_boxes の使い方

 下記、HTMLのような、チェックボックスを `collection_check_boxes`を使用して、いい感じに表示させる。

```sample.html
<form action="cgi-bin/abc.cgi" method="post">
  <p>
    <input type="checkbox" name="riyu" value="1">選択肢 - 1
  </p>
  <p>
    <input type="checkbox" name="riyu" value="2">選択肢 - 2
  </p>
  <p>
    <input type="checkbox" name="riyu" value="3">選択肢 - 3
  </p>
  <p>
    <input type="submit" value="送信する">
  </p>
</form>
```

<br>

**スクリーンショット**
![2018-01-24 18.16.03.png](https://qiita-image-store.s3.amazonaws.com/0/158112/c64d621e-eb07-bc93-f668-ba9f96126023.png)





## collection_check_boxes を用いてみる

<br>

```check_boxes.haml

= form_for(user) do |f|
  = f.label :name
  = f.text_field :name

  = f.collection_check_boxes :drink_ids, @drinks, :id, :name do |b|
    = b.label { b.check_box + b.text }

  = f.submit '送信', class: 'btn'

```


```btn.css

.btn{
    display: inline-block;
    padding: 0.5em 1em;
    text-decoration: none;
    background: #668ad8;
    color: #FFF;
    border-bottom: solid 4px #627295;
    border-radius: 3px;
}

```

<br>

**スクリーンショット**
![2018-01-24 15.17.29 1.png](https://qiita-image-store.s3.amazonaws.com/0/158112/a7ac567a-0034-70d1-b562-3908c4a4f9d2.png)


なんだか、チェックボックス と テキストの感覚が ギュン と近すぎて気持ち悪い...orz



------------------------





```check_boxes.haml

= form_for @user do |f|
  = f.collection_check_boxes :reason_ids, @choices, :id, :content do |b|
    = b.check_box
    = b.label { box.text }
  = f.submit '送信', class: 'btn'

```

<br>

**スクリーンショット**

![2018-01-24 15.06.16.png](https://qiita-image-store.s3.amazonaws.com/0/158112/8b18881e-2199-9c11-75c3-46dedc1870b3.png)


いい感じになった☺



## Option

上記の form のままだと パラメーターの配列の先頭に `' '`
空の 値が含まれるので, option で 

```check_boxes_option.rb
  f.collection_check_boxes :reason_ids, @choices, :id, :content, include_hidden: false do |b|
```
のように option で 先頭の空の値をなくすことができる。

また, 1行で 書くこともできる

```check_boxes_one_line.rb
  = f.collection_check_boxes :drink_ids, @drinks, :id, :name, include_hidden: false, class: 'hoge'
```
1行で書くと, classなど html のoptionの与え方がややこしくなるので、僕は ネストさせた方が好きです。



<br>

## 余談

```users_table.

+----+-----------+---------------------+---------------------+
| id | name      | created_at          | updated_at          |
+----+-----------+---------------------+---------------------+
|  1 | タケシ     | 2018-01-24 09:22:21  | 2018-01-24 09:22:21 |
|  2 | サトル     | 2018-01-24 09:22:41  | 2018-01-24 09:22:41 |
|  3 | ハナコ     | 2018-01-24 09:23:11  | 2018-01-24 09:23:11 |
+----+-----------+---------------------+---------------------+

```


```drinks_table.

+----+--------------------+---------------------+---------------------+
| id | name               | created_at          | updated_at          |
+----+--------------------+---------------------+---------------------+
|  1 | コーヒ               | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  2 | コーラ               | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  3 | お茶                | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  4 | 紅茶                | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  5 | ミルクティ            | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
|  6 | 水                 | 2018-01-24 09:01:14 | 2018-01-24 09:01:14 |
+----+--------------------+---------------------+---------------------+

```

```drink_users_table.

+----+----------+---------+---------------------+---------------------+
| id | drink_id | user_id | created_at          | updated_at          |
+----+----------+---------+---------------------+---------------------+
|  1 |        2 |       1 | 2018-01-24 09:22:21 | 2018-01-24 09:22:21 |
|  2 |        1 |       2 | 2018-01-24 09:22:41 | 2018-01-24 09:22:41 |
|  3 |        6 |       2 | 2018-01-24 09:22:41 | 2018-01-24 09:22:41 |
|  4 |        3 |       3 | 2018-01-24 09:23:11 | 2018-01-24 09:23:11 |
+----+----------+---------+---------------------+---------------------+
```

こんな感じ🤔

**スクリーンショット**
![2018-01-24 18.35.20.png](https://qiita-image-store.s3.amazonaws.com/0/158112/9ab4ed8d-2c64-4192-b73e-7531b2302050.png)



`drinks/new` も動かせば, 飲み物の選択肢を 増やすことができるので、イレギュラーにも対応できます☺

<br>
<br>
### 参考

- [collection_check_boxes (ActionView::Helpers::FormOptionsHelper) - APIdock](https://apidock.com/rails/v4.0.2/ActionView/Helpers/FormOptionsHelper/collection_check_boxes)
- [railsで多対多な関係を実装する時のポイント（加筆修正するかも）](https://qiita.com/m-shin/items/0487105994d9281221d4)
- [Rails4でcollection_check_boxesを使って、多対多の関連をチェックボックスで設定する](https://qiita.com/hamichamp/items/8cf980e6d5ca9fd7e96f)