Edited at

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

More than 1 year has passed since last update.


はじめに

Rails 4.0.2以降から使用できる

ViewHelper の collection_check_boxes を使用しようとして少し詰まったので、

簡単なアプリケーションを作成してみて、楽しく覚えてみた。


環境


  • Ruby: 2.4.0

  • RoR: 5.0.6

  • haml


やりたいこと


User を 作成するときに 飲み物(Drink)を 選択して create できる。

プラスα - 選択肢にない飲み物(Drink)が 出てきたら 飲み物も新規登録できるように。

いわゆる、

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


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

あれ、、、全部覚えてられないな。。。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 |
+----+--------------------+---------------------+---------------------+




これだけで

/users/newに アクセスすると、

人の名前を入力して、飲みモノを 選んで, データを作成することができる。






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>


スクリーンショット


collection_check_boxes を用いてみる



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;
}



スクリーンショット

なんだか、チェックボックス と テキストの感覚が ギュン と近すぎて気持ち悪い...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'



スクリーンショット

いい感じになった☺


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の与え方がややこしくなるので、僕は ネストさせた方が好きです。



余談


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 |
+----+----------+---------+---------------------+---------------------+

こんな感じ🤔

スクリーンショット

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






参考