railsで複数選択可能なcheckboxのタグ設定を開発したのでメモ。
やりたいこと
- rails7
- userにタグを設定したい
- タグは運営が設定しているものから選ぶ
- 複数一括で設定できる
- checkboxで選択する
全体の流れ
- tag model作成
- tag_map model作成
- checkboxのform作成
今回は中間テーブルがある形のタグを開発する。
tag model作成
下記のdb設計で中間テーブルtag_mapを作成する。
tag
- name
- description
tag_map
- tag_id
- user_id
tag model
class Tag < ApplicationRecord
has_many :tag_maps, dependent: :destroy
has_many :users, through: :tag_maps
end
tag_map
class TagMap < ApplicationRecord
belongs_to :tag
belongs_to :user
validates :tag_id, :user_id, presence: true
end
上記でtagとtag_mapを関連付けする。
checkbox
formの要件
- 複数のタグを一括で付与できる
- 前に設定しているタグはcheckedに
- 逆にcheckを外したら中間テーブルのレコードを削除する
controllerで保存
def update
ActiveRecord::Base.transaction do
@user = User.find(current_user.id)
if @user.update(user_params)
@user.tag_maps.where.not(industry_id: @user.tag_ids).destroy_all
if @user.tag_ids.present?
@user.tag_ids.each do |tag_id|
TagMap.find_or_create_by(user_id: @user.id, tag_id: tag_id)
end
end
end
redirect_back(fallback_location: root_path)
flash[:notice] = "編集が完了しました"
rescue => e
puts e
redirect_back(fallback_location: root_path)
flash[:alert] = "編集できませんでした"
end
end
- @user.tag_maps.where.not(industry_id: @user.tag_ids).destroy_allではまず、
@user.tag_maps
でUserに関連するTagMapのリストを取得します。そしてwhere.not(tag_id: @user.industry_ids)
で、ユーザのtag_idsに含まれていないものを抽出します。これにより、ユーザと関連づけられているもののうち、現在のリクエストで削除されることになっているTagMapが選ばれます。その後、destroy_all
メソッドで選ばれたすべてのTagMapを削除します。 - @user.tag_ids.present?はすべてのtagのcheckを外した際にnilになりエラーになるので、事前にnilじゃないかを確認します。
@user.tag_ids.each do |tag_id|
TagMap.find_or_create_by(user_id: @user.id, tag_id: tag_id)
end
- 上記ではフォームから送信された、ユーザに関連付けるtagのIDのリストをループ処理します。
TagMap.find_or_create_by(user_id: @user.id, tag_id: tag_id)
すでに同じものがあるかを確認し、なければ作成。
form
<% @tags.each do |tag| %>
<%= tag.name %>
<%= form.check_box :tag_ids, { multiple: true, checked: @user.tags.include?(tag), class: "checkbox_check" }, tag.id, nil %>
<% end %>
-
:tag_ids
はこのチェックボックスが表す属性(ここではユーザが持つタグのID)を指定しています。 -
{ multiple: true, checked: @user.tags.include?(tag), class: "checkbox_check" }
はチェックボックスのオプションを指定しています。-
multiple: true
は複数選択可能なチェックボックスであることを示しています。 -
checked: @user.tags.include?(tag)
はチェックボックスがチェックされているかどうかを決定します。ユーザが持っているタグに現在のタグが含まれていればチェックされます。 -
class: "checkbox_check"
はチェックボックスにCSSクラスを適用するためのものです。
-
-
tag.id, nil
はチェックボックスがチェックされた場合とされていない場合の値を指定しています。チェックされた場合はタグのIDが、チェックされていない場合はnil
がフォームから送信されます。