article -< article_categories >- categories であれば基本に忠実にcollection_check_boxesを使えば良い。
今回article -< article_categoriesだけのパターンに出会ってハマったのでメモ。
article_categoriesにcategory_idがenumで定義されてるパターン。
%= form_with(model: @article, local: true) do |f| %>
<%= f.collection_check_boxes :category_names, ArticleCategory.category_id.options, :last, :first %>
<%= f.submit %>
<% end %>
class Article < ApplicationRecord
has_many :article_categories
def category_names
article_categories.map(&:category_id)
end
end
class ArticleCategory < ApplicationRecord
belongs_to :article
extend Enumerize
enumerize :category_id, :in => { tech: 1, buisiness: 2, sports: 3 }
end
class ArticlesController < ApplicationController
def update
# トランザクションは一旦無視
@article = Article.find(params[:id])
@article.assign_attributes(article_params)
if article_category_names = params.dig(:article, :article_category_names)
@article.company_decidable_divisions.destroy_all
article_category_names.each do |name|
@article.article_categories.build(category_id: name)
end
end
if @article.save
else
end
end
private
def article_params
params.require(:article).permit(:title)
end
end
登録されてるものはチェックされた状態で出力されてほしい。
<%= f.collection_check_boxes :category_names, ArticleCategory.category_id.options, :last, :first %>
第一引数と第二、三、四引数の関係性が大事。fがもってる第二引数のメソッドの返り値に、valueとして出力されるものが含まれていたらチェックされた状態になるっぽい。今回valueにはtechとかchildが入ってくるのでfのcategory_namesというメソッドではそれらが返るようにした。
普通のcollection_check_boxesだとf.collection_check_boxes :category_idsのように指定する(article.category_ids(→ singular_idsなので[1, 2]などが返る))が今回はenumで管理されていたのでハマったよと言う話でした。