ターゲットするER図
belongs_to, has_many で関連付けを行う
上記のER図において、『日報は投稿者しか更新削除できない』というようにしたい。そのためには日報にユーザ情報が必要なので、日報テーブルにユーザIDの外部キーを導入する。
以下では、日報テーブルにユーザIDの外部キー以外を登録してあったテーブルに対して、外部キーを追加する流れを記述。
と言うわけで、日報テーブルにユーザIDカラムを追加するために、まずはマイグレーションファイルを rails g
コマンドで大枠を作る。
rails g migration AddUserIdToReports
生成されたマイグレーションファイルに、ユーザーIDの外部キーを追加するコードを書く。
class AddUserIdToReports < ActiveRecord::Migration[6.1] def change add_reference :reports, :user, foreign_key: true end end
そして、データベースを移植する。
% rails db:migrate Running via Spring preloader in process 87420 == 20220906140109 AddUserIdToReports: migrating =============================== -- add_reference(:reports, :user, {:foreign_key=>true}) -> 0.0069s == 20220906140109 AddUserIdToReports: migrated (0.0069s) ======================
ここまでで、ユーザID用を追加した日報テーブルが用意できた。次は、日報とユーザの関連を定義するために、日報モデルに belongs_to
で関連付けを行う。
1つの日報は、特定のユーザに紐づくため :user
は単数系。
# app/model/report.rb class Report < ApplicationRecord belongs_to :user end
関連付けを行うことで、ユーザIDがないと日報が作れないようになる。
次は、ユーザ情報を日報インスタンスに紐づける必要がある。
試しにコンソール上で少し試してみる。下記のように、現状はユーザインスタンスから日報メソッドを操作することができない。
紐づいているユーザで日報を作成するために、 has_many
で複数所有の関連付けを行う。ここで、ユーザが消滅したら日報も同時に消滅させるために、:destroy
タグをつけておく。ちなみに複数所有するので、 reports
と複数形になっている。
# app/models/user.rb ... has_many :reports, dependent: :destroy ...
上記の設定で、ユーザインスタンスを通して日報メソッドを操作できるようになった。
ここまでできたら、最後はユーザインスタンスを通して、日報オブジェクト生成をしてあげられるようにする。
ビューで呼び出される create
メソッドを下記のように変更する。
# app/controllers/reports_controller.rb ... # POST /reports or /reports.json def create # 変更前 @report = Report.new(report_params) # 変更後 @report = current_user.reports.build(report_params) # 変更後(new も使えるらしい。が、慣習的にbuildを使うらしい) # @report = current_user.reports.new(report_params) ...
試しに入力する。
無事完了🤗
あとは、投稿したユーザのみ日報を更新・削除できると言う部分について。
日報一覧と日報詳細ビューに if report.user == current_user
みたいな感じで、ログインユーザとレポートユーザが一致するとき、更新・削除ボタンを表示するに変更した。