Rails 多対多テーブル構造をcollection_check_boxesで関連付ける

formを用いた際の多対多テーブルの関連付けを、collection_check_boxesを使用して行う。

railsdoc.com

テーブル構造

create_table "users", force: :cascade do |t|
  t.string   "name"
  t.datetime "created_at"
  t.datetime "updated_at"
end

create_table "services", force: :cascade do |t|
  t.string   "name"
  t.datetime "created_at"
  t.datetime "updated_at"
end

create_table "users_services", force: :cascade do |t|
  t.integer  "user_id"
  t.integer  "service_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

モデル

class User < ApplicationRecord
  has_many :users_services
  has_many :services, through: :users_services
end
class Service < ApplicationRecord
  has_many :users_services
  has_many :users, through: :users_services
end
class UsersService < ApplicationRecord
  belongs_to :user
  belongs_to :service
end

コントローラー

class UsersController < ApplicationController
  def new
    @user = User.new
    @services = Service.all
  end

  def create
    user = User.new(permit_params)
    user.save!
  end

  private

  def permit_params
    params.require(:user).permit(:name, service_ids: [])
  end
end

User モデルの service_ids メソッドに対して値を送信できるようにビューの定義を行う。

ビュー

※slim構文にて定義

= form_with scope: :user, mdoel: @user, url: users_path do |form|
  = form.text_field :name
  = form.collection_check_boxes :service_ids, @services, :id, :name, include_hidden: false
  = form.submit 'post'

collection_check_boxesservices テーブルに登録したレコードのID・名称を展開して表示を行う。 include_hidden は空白文字をhiddenで定義するかオプションで設定を変更できる(不要なので今回はfalse)。

任意の内容で入力を行いsubmitすると、関連も含めてレコードを保存できる。

web_1  | Started POST "/users" for 172.18.0.1 at 2023-05-03 07:46:45 +0000
web_1  | Cannot render console from 172.18.0.1! Allowed networks: 127.0.0.0/127.255.255.255, ::1
web_1  | Processing by UsersController#create as TURBO_STREAM
web_1  |   Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"name"=>"test", "service_ids"=>["1", "2"]}, "commit"=>"post"}
web_1  |   Service Load (0.3ms)  SELECT `services`.* FROM `services` WHERE `services`.`id` IN (1, 2)
web_1  |   ↳ app/controllers/users_controller.rb:8:in `create'
web_1  |   TRANSACTION (0.2ms)  BEGIN
web_1  |   ↳ app/controllers/users_controller.rb:9:in `create'
web_1  |   User Create (0.7ms)  INSERT INTO `users` (`name`, `created_at`, `updated_at`) VALUES ('test', '2023-05-03 07:46:45.726583', '2023-05-03 07:46:45.726583')
web_1  |   ↳ app/controllers/users_controller.rb:9:in `create'
web_1  |   UsersService Create (0.6ms)  INSERT INTO `users_services` (`user_id`, `service_id`, `created_at`, `updated_at`) VALUES (1, 1, '2023-05-03 07:46:45.730791', '2023-05-03 07:46:45.730791')
web_1  |   ↳ app/controllers/users_controller.rb:9:in `create'
web_1  |   UsersService Create (0.2ms)  INSERT INTO `users_services` (`user_id`, `service_id`, `created_at`, `updated_at`) VALUES (1, 2, '2023-05-03 07:46:45.732966', '2023-05-03 07:46:45.732966')
web_1  |   ↳ app/controllers/users_controller.rb:9:in `create'
web_1  |   TRANSACTION (7.5ms)  COMMIT
web_1  |   ↳ app/controllers/users_controller.rb:9:in `create'
web_1  | No template found for UsersController#create, rendering head :no_content
web_1  | Completed 204 No Content in 60ms (ActiveRecord: 10.1ms | Allocations: 11039)