Oteto Blogのロゴ

【Rails】collection_check_boxesで多対多の関連付けをする方法

やりたいこと

UserテーブルとLessonテーブルの関係を表したER図

  • 上のようなテーブル構成
    • UserテーブルとLessonテーブルは多対多の関係
    • 1人のユーザーは複数のLessonを履修している
  • User登録時、チェックボックスで選択したLessonとそのUserを結びつけたい
  • モデルからチェックボックスを自動生成したい

解決法

collection_check_boxesというビューヘルパーメソッドを使う。

<%= form_for @user,url:admin_users_path do |form| %>
  <%= form.collection_check_boxes(:lesson_ids, @lessons, :id, :name) do |lesson| %>
    <%= lesson.check_box %>
    <%= lesson.text %>
  <% end %>
<% end %>

今回の例の場合、上記のようにすることでLessonテーブルのレコードに応じてチェックボックスが生成される。

実装例

環境

  • Ruby 2.6.5
  • Rails 5.2.4.3

モデル

class User < ApplicationRecord
  has_secure_password
  has_many :take_lessons,dependent: :destroy
  has_many :lessons,through: :take_lessons
end
class Lesson < ApplicationRecord
  has_many :take_lessons,dependent: :destroy
  has_many :users,through: :take_lessons
end
class TakeLesson < ApplicationRecord
  belongs_to :user
  belongs_to :lesson
end

コントローラ

class Admin::UsersController < Admin::Base
  def new
    @user = User.new
    @lessons = Lesson.all
  end

  def create
    @user=User.new(user_params)
    @user.admin=false
    @lesson_ids=params[:user][:lesson_ids]
    @lesson_ids.shift
    if @user.save
      @lesson_ids.each do |lesson_id|
        lesson = Lesson.find(lesson_id.to_i)
        @user.lessons << lesson #関連付ける
      end
      flash[:notice] = "生徒を追加しました"
      redirect_to("/admin/users")
    else
      flash[:notice] = "生徒を追加できませんでした"
      redirect_to("/admin/users/new")
    end
  end

  def user_params
    params.require(:user).permit(:name, :faculty, :grade, :student_id, :password, :password_confirmation)
  end
end

ビュー

<h2>ユーザー追加</h2>
<%= form_for @user,url:admin_users_path do |form| %>
  <%= form.collection_check_boxes(:lesson_ids, @lessons, :id, :name) do |lesson| %>
    <ul>
       <li>
         <%= lesson.check_box %>
         <%= lesson.text %>
       </li>
    </ul>
  <%end%>
  <%= form.submit("追加する") %>
<%end%>