collection_check_boxesの挙動

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で管理されていたのでハマったよと言う話でした。