railsで複数選択可能なcheckboxでタグ設定

目次

マーケター、エンジニアを月1時間からジョインできるプラットフォーム

airteamは月1時間からマーケターやエンジニアに相談できるプラットフォーム。 雇うのはハードル高いけどプロをチームに入れたい。そんな経営者のためのサービスです。 相談にのる方も募集しています。

タスクなしだから月一時間からジョイン可能

作業はなくオンライン相談メイン。 月1時間からさっと経験者に継続的に相談できます。

多様な経験者を雇用するより何倍も早くチームに

あらゆるジャンルの経験者がいるので あなたのチームのノウハウの選択肢が広がります。

NDAはすでに締結済み、契約もスムーズ

契約の煩雑なやりとりはなく、NDAはすでに締結済み、書面のやりとりはありません。

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がフォームから送信されます。