Help us understand the problem. What is going on with this article?

【Rails】複数のチェックボックスの値を配列でPOSTする【collection_check_boxes】

まえがき

Ruby on RailsのFormで、複数のチェックボックスの値をまとめて扱いたい状況って、割とよくあるんじゃないかなと思います。
・検索で、都道府県を複数選択
・タグ付けするときに複数タグをチェックボックスで選択
などなど。。。

その際に取れる選択肢は
1. check_box_tag 'prefecture[]'のように、check_box_tagでべた書きする
2. collection_check_boxesを使う
が主になるかなと思います。

せっかくRailsを利用する以上、form_for(Rails5ではform_withも)のhelperに乗っかっていきたい!
ということで、2のcollection_check_boxesを使う方法について記載します。

ないよう

collection_check_boxesについて

まず、collection_check_boxesですが、
・form_forのビルダーを用いるもの

collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)

・そのまま使えるもの

collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)

2種類があります。違いは、第一引数にobjectを受けるかどうかです。
form_forのビルダーを用いるものの場合は、第一引数にform_forのヘルパー内で保持しているオブジェクトが自動で渡されるため、省略されています。

引数の解説

object

フォーム全体の更新対象になるオブジェクトです。
オブジェクトは、特に何も指定しない場合の初期値の設定に用いられます。

method

objectに対して、この一連のチェックボックスが対応するメソッドを指定します。
そのため、objectにこのメソッドが実装されていないと、エラーで落ちます。
ここは、初期値の指定と、特に指定しない場合チェックボックスタグのnameの値(つまりパラメータのkey)に使われます。
object.methodの値が下のvalue_methodの結果と一致していると、checked状態になります。

collection

実際にチェックボックスを生成する際に使われるcollectionです。
配列とか、ActiveRecord::Relationならはいるっぽいです。
なので、第一引数、第二引数と全く無関係のオブジェクトでも動きます。

value_method, text_method

ほぼ一緒なのでまとめて。
collectionの各要素に、対して呼ばれるメソッドです。
collectionの要素数分チェックボックスが作られるわけですが、それぞれのtext、valueに設定される値がこのメソッドを呼んだ結果になります。

options, html_options

ちょっと多い上に基本的な使い方は他のview_helperと変わらないので、省略します。
初期選択とか、値を0,1じゃなくす、idとかclassを加える、とかはこのへんでやります。

&block

生成されるチェックボックスの形とかラベルを変更したいときに使います。省略するとcollection.textがラベルにくっつきます。
気力があれば別で書きます。

おおまかな使い方

ActiveRecordの関連が
object >-< collection
的な感じだとかなり楽に使えます。
例えば、あるユーザーに複数の都道府県を関連付ける、みたいなとき
User >-< Prefecture

class User
  has_many :user_prefectures
  has_many :prefectures, through: :user_prefectures
end

class UserPrefecture
  belongs_to :user
  belongs_to :prefecture
end

class Prefecture
  # 都道府県名がnameに入っているとする
  has_many :user_prefectures
end

みたいな感じだとして、controllerから更新対象のUserが@userに格納されて渡されているとすると、

<%= form_for @user |f| do %>
  <%= f.collection_check_boxes :prefectures, Prefecture.all, :id, :name %>
<% end %>

のような形でかけます。
結果は(いろいろ省略しますが)、

<form>
    <input type="hidden" name="user[prefectures][]" value="">
    <input type="checkbox" value="1" name="user[prefectures][]" id="user_prefecturs_1">
    <label for="user_prefecturs_1">北海道</label>
    <input type="checkbox" value="2" name="user[prefectures][]" id="user_prefecturs_2">
    <label for="user_prefecturs_1">青森</label>
  <!--
  省略
  -->
    <input type="checkbox" value="47" name="user[prefectures][]" id="user_prefecturs_47">
    <label for="user_prefecturs_47">沖縄</label>
</form>

みたいなのができるはずです。

※もし、DBにない値をチェックボックスの候補で使いたい場合
いろいろやり方はあるとは思いますが、ActiveModelを用いて、ActiveRecordっぽいクラスを作っちゃうのが楽です。

class Prefecture
  include ActiveModel::Model
  attr_accessor :id, :name
  # 長くなるんで全部は書きません
  ALL = %w[北海道 青森 秋田].map.with_index(1) {|name, index| new(id: index, name: name)}.freeze
end

みたいなクラスを作って、collectionにこいつを指定してあげればよいです。
検索フォームなどだと値をDBに保存しないので、FormObjectを使ったりすると思うので、FormObjectにprefecturesメソッドを実装してあげればいい感じになります。
(ちょっと気力がないので、気力があれば追記します。)

おわりに

collection_check_boxes、うまく使うとviewがかなりスッキリします。
よかったら使ってみて下さい。
マサカリお待ちしております。

参考にした記事

https://qiita.com/sho012b/items/3a595fde14516081dff5

RaimuEr
Railsのお仕事してます。 オブジェクト指向難しいです。 お酒が好きで、飲み漁っています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした