collection_check_boxesで登録済みの値にチェックをつけて表示する方法を調べた
Railsで多対多のリレーションのモデルをチェックボックスで表現する際にcollection_check_boxes
と言うViewヘルパー関数を使うと便利。
しかし編集時など、登録した値は当然チェックがついた状態で表示されないと困るが、どういう仕組みかの説明が見当たらなかったので調べた。
前提
下記のようなリレーションとなっていることを前提とする。
◆リレーション post <--> author_post <--> author ◆model定義 class Post < ApplicationRecord has_many :author_posts has_many :authors, through: author_posts ... class Author < ApplicationRecord has_many :author_posts has_many :posts, through: :author_posts ... class AuthorPost < ApplicationRecord belongs_to :post belongs_to :author
viewにcollection_check_boxesを下記のように設置
= collection_check_boxes(:post, :author_ids, Author.all, :id, :name) do |b| = b.label { b.check_box + b.text } formオブジェクトを使う場合 = f.collection_check_boxes(:author_ids, Author.all, :id, :name) do |b| = b.label { b.check_box + b.text } # ※viewにAuthor.allを直接記述するのはよくない
:id
と:name
は下記のように展開される
<input type="checkbox" value="4" checked="checked" name="post[author_ids][]" id="post_author_ids_4"> value : authorのID id : post_{第2引数の文字列}_{authorのID}
各項目の意味
各引数の役割はそれぞれ下記の通り
:post
更新対象のオブジェクト(のシンボル名)。form_forでは省略可。
:author_ids
更新対象のオブジェクトが持つメソッド(のシンボル名)。チェックボックスの各チェックに関連付けられるID。登録や更新の際にparameterに含まれるので、StrongParameterの対応が必要。
# app/controller/posts_controller.rb def post_params params.require(:post).permit(:title, { author_ids: [] }) end # ここで定義しないと「Unpermitted parameter: author_ids」となって登録や更新がされない。
:id
chekcboxのinputタグにてid属性に割り振られる値。かつ、登録済みの値かどうかを比較する対象となる属性(後述)。authorが持つメソッドを指定。
:name
チェックボックスに表示されるinputタグのテキストとなる値。authorが持つメソッドを指定。
# 例えばauthorが下記メソッドを持つ場合、:nameのところで代替可能 def honorific name + '様' end
まとめ
今回分かってよかったのが、第2、4引数(form_forの場合は第1、3引数)であるauthor_ids
と:id
の関係。
post(正確には第1引数のオブジェクト)はauthor_ids
というメソッドを持っており、その結果と第4引数id
を比較し、合致する場合にチェックボックスにチェックが付いた状態で画面表示される。(第4引数のidは、第3引数のそれぞれのオブジェクトが持つid。今回ではAuthor.allのそれぞれのauthorのauthor.id)
例えばpostに紐付くauthorのidが1,3,4の場合、post.author_ids = [1,3,4]となり、 Author.allの各authorのidと比較し、合致する場合にcheck属性が付与される。
上記を理解しておけば、登録した値が編集画面でチェックされていない、という場合にも原因の切り分けがしやすくなるので、覚えておこう。