背景
上司からのコードレビューで理解するのに時間がかかった部分があったので記録する
指摘された内容
class BlockedStaff < ApplicationRecord
belongs_to :user
belongs_to :staff
validates :user_id, uniqueness: { scope: :staff_id } # 指摘された部分
end
これは、ユーザーがブロックしているスタッフを管理しているモデルです
ユーザーは同じスタッフをブロックできないように、ユーザーとスタッフでユニーク制約がかけられています
指摘されたのはこの部分
validates :user_id, uniqueness: { scope: :staff_id }
意味合いとしては
validates :staff_id, uniqueness: { scope: :user_id }じゃない?
このようなレビューをいただきました
レビューについて
機能としてはどちらで記述しても、ユニーク制約のバリデーションはかかります
しかしレビュー通り意味は違ってきます
validates :user_id, uniqueness: { scope: :staff_id }の意味
-
user_idに対してバリデーションがかかっている -
scope: :staff_idなので、「staff_idが同じレコード」が対象です
「staff_idが同じレコード群の中で、user_idが重複していないか」をチェックしている
validates :staff_id, uniqueness: { scope: :user_id }の意味
-
staff_idに対してバリデーションがかかっている -
scope: :user_idなので、「user_idが同じレコード」が対象
「user_idが同じレコード群の中で、staff_idが重複していないか」をチェックしている
なぜvalidates :user_id, uniqueness: { scope: :staff_id }が間違っているのか?
class BlockedStaff < ApplicationRecord
belongs_to :user
belongs_to :staff
validates :user_id, uniqueness: { scope: :staff_id } # 指摘された部分
end
BlockedStaffは、ユーザーがブロックしたスタッフを管理するモデルです、なので操作の主体はユーザーです
なのでvalidates :user_id, uniqueness: { scope: :staff_id }だと下記のイメージ
-
staff_idが同じレコードに絞る - その中で
user_idが重複していないかをチェックする
つまり、ユーザーが行う操作にも関わらずstaff_idの視点でバリデーションを行っています
逆にvalidates :staff_id, uniqueness: { scope: :user_id }の場合は
-
user_idが同じレコードに絞る - その中で
staff_idが重複していないかをチェックする
これはuser_idの視点でバリデーションが行われています
なので正しくは
class BlockedStaff < ApplicationRecord
belongs_to :user
belongs_to :staff
validates :staff_id, uniqueness: { scope: :user_id } # 修正
end
具体的に何が変わるの?
意味合いだけでなく、実際の挙動にも違いがあります
validatesは、第一引数に指定したカラムに対してエラーメッセージを付与します
# validates :user_id の場合
blocked_staff.errors[:user_id]
# => ["has already been taken"]
# validates :staff_id の場合
blocked_staff.errors[:staff_id]
# => ["has already been taken"]
つまり、どちらのカラムにバリデーションをかけるかによって、エラーメッセージが付くカラムが変わります
BlockedStaffはユーザーがスタッフをブロックする操作なので、バリデーションエラーは「ブロックしようとしたスタッフ(staff_id)」に対して出る方が自然です
validates :user_idだと「ユーザーIDが重複しています」というエラーになり、操作しているユーザーからすると意味が伝わりにくくなります
感想
- ん?となりながら理解できたことを言語化できたので良かったです
- 可読性の高いコードを書く重要性が学べた
参考