はじめに
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
class User < ApplicationRecord
has_many :drink_users
has_many :drinks, through: :drink_users
accepts_nested_attributes_for :drink_users, allow_destroy: true
end
class Drink < ApplicationRecord
has_many :drink_users
has_many :users, through: :drink_users
end
class DrinkUser < ApplicationRecord
belongs_to :user, optional: true
belongs_to :drink, optional: true
end
Controller
users の new に Drink を 用意しておく
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
= 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
%W[コーヒ コーラ お茶 紅茶 ミルクティ 水].each { |a| Drink.create(name: a) }
よく お頼みになる飲み物を seedファイルで予め用意しておく。
rails db:seed
の実行を忘れずに。
+----+--------------------+---------------------+---------------------+
| 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
を使用して、いい感じに表示させる。
<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 を用いてみる
= 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{
display: inline-block;
padding: 0.5em 1em;
text-decoration: none;
background: #668ad8;
color: #FFF;
border-bottom: solid 4px #627295;
border-radius: 3px;
}
なんだか、チェックボックス と テキストの感覚が ギュン と近すぎて気持ち悪い...orz
= 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 で
f.collection_check_boxes :reason_ids, @choices, :id, :content, include_hidden: false do |b|
のように option で 先頭の空の値をなくすことができる。
また, 1行で 書くこともできる
= f.collection_check_boxes :drink_ids, @drinks, :id, :name, include_hidden: false, class: 'hoge'
1行で書くと, classなど html のoptionの与え方がややこしくなるので、僕は ネストさせた方が好きです。
余談
+----+-----------+---------------------+---------------------+
| 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 |
+----+-----------+---------------------+---------------------+
+----+--------------------+---------------------+---------------------+
| 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 |
+----+--------------------+---------------------+---------------------+
+----+----------+---------+---------------------+---------------------+
| 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
も動かせば, 飲み物の選択肢を 増やすことができるので、イレギュラーにも対応できます☺
### 参考