...

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

Railsのcollection_check_boxesメソッド

どうもおはようポテトです。

突然ですが。Railsで「大学の生徒の履修科目を管理するシステム」を作るとします。

その生徒が履修する科目を編集する画面では、

上のように科目の数だけチェックボックスが表示され、「チェックボックスで選択した科目とその生徒を結びつけたい」とします。

そこで多くの方が抱く疑問がこちら。

 

チェックボックスを自動で生成する方法ないかな?

ということで今回は

「モデルからチェックボックスを自動生成したい」

「そこから多対多の関係であるモデル達のレコードを関連付けさせたい」

という方に向けてcollection_check_boxesというビューヘルパーについて実際に使ってみてまとめました。

自分の備忘録でもありますが、ぜひ参考にしていただければ幸いです⸝⸝- ̫ -⸝⸝

ブログ主

早速いってみよう!

やりたいこと

このように3つのテーブルがあり、

UserテーブルとLessonテーブルは多対多の関係

一人のユーザーは複数の科目を履修している

新しいユーザーを追加する時に、そのユーザが履修している科目(lesson)をチェックボックスで選択し送信することでそのユーザーと科目を関連づけたい

やりたいことはこんな感じ。

そんな時にcollection_check_boxesというビューヘルパーメソッドを使えばちょっと楽になります。

まずは使い方を見てみよう!

ソロモン

collection_check_boxesの使い方

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%>

今回は上のようにform_for下で使いました。

すると無事、科目それぞれのチェックボックスが生成されました。

ブロック内でlessonという引数に対してcheckboxを呼ぶことでチェックボックスを、そしてtextを呼ぶことでそれぞれの科目名を表示しています。

ブログ主

めっちゃ楽やん

引数について

<%=form.collection_check_boxes(:lesson_ids, @lessons, :id, :name) do |lesson|%>

引数がいっぱいあり困惑すると思うので少しだけ解説を。

 

引数の説明

第一引数(:lesson_ids)

→ドキュメントによるとメソッドを指定するらしい。まあparamsで取り出す時の名前ぐらいに考えればいいかも。

第二引数(@lessons)

→リレーショナルオブジェクトを指定する。ここでは全ての科目が入った@lessonsを指定している。

第三引数(:id)

→inputタグでいうvalue的なもの。ここではlessonテーブルのidカラムを指定している。

第四引数(:name)

→inputタグのテキスト的なもの。ここではlessonテーブルのnameカラムを指定している。

受け取り方

"user"=>{"student_id"=>"a", "faculty"=>"a", "grade"=>"a", "name"=>"a", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "lesson_ids"=>["", "1", "2", "3"]}

3つあるチェックボックス全てにチェックして送信した場合、パラメータは以上のようになっていました。

第一引数で指定した「lesson_ids」というキーで渡されています。

(※先頭の要素が空なのは謎…)

 

@lesson_ids=params[:user][:lesson_ids]

なのでこれで取り出すことができます。

ブログ主

そこまで難しい知識はいらなかったね

余談

<%=collection_check_boxes(@user, :lesson_ids, @lessons, :id, :name) do |lesson|%>

第一引数にはこのように本来取り扱うモデルのオブジェクトを先頭で指定する必要があるのですが、今回のようにform_for下で記述する場合などは要らないそうです。

collection_check_boxesを使ってみた

実際にcollection_check_boxesメソッドを使って、上で述べたやりたいことをやってみました。

環境

Ruby 2.6.5

Rails 5.2.4.3

モデル

Userクラス

class User < ApplicationRecord
  has_secure_password
  has_many :take_lessons,dependent: :destroy
  has_many :lessons,through: :take_lessons
end

 

Lessonクラス

class Lesson < ApplicationRecord
  has_many :take_lessons,dependent: :destroy
  has_many :users,through: :take_lessons
end

 

TakeLessonクラス

class TakeLesson < ApplicationRecord
  belongs_to :user
  belongs_to :lesson
end

コントローラ

users_controller

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

params[:user][:lesson_ids]で取得できるハッシュの先頭の要素がなぜか空になるのでshiftメソッドを使ってます。

ビュー

new.html.erb

<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%>

結果

適当な入力で試したところ…

 

無事、関連付けされてました(っ´ω`c)

お疲れ様!

ソロモン

結論:collection_check_boxes便利だね

以上になります。

参考になれば幸いです!では⸝⸝- ̫ -⸝⸝

参考になったらシェアしよう

コメントを残す

メールアドレスが公開されることはありません。

CAPTCHA