背景
Webアプリケーションにおいて、ユーザーが特定の条件下でのみデータを作成できるように制限する必要がある場合がよくあります。特に、予約システムにおいては、一人のユーザーが一つの企業に対して、未来に一つの予約しか持てないようにすることが望ましいケースがあります。
この記事では、Ruby on Railsを使用して、このようなビジネスルールを実装する方法を解説します。
モデルのバリデーション設定
カスタムバリデーションをReservation
モデルに追加することで、上記のルールを適用します。
class Reservation < ApplicationRecord
belongs_to :customer
belongs_to :company
validate :unique_future_reservation_per_customer_and_company
private
def unique_future_reservation_per_customer_and_company
return if date.blank? || customer_id.blank? || company_id.blank?
future_reservations = Reservation.where(customer_id: customer_id, company_id: company_id).where('date >= ?', Date.today)
future_reservations = future_reservations.where(deleted_at: nil)
future_reservations = future_reservations.where.not(id: id) unless new_record?
if future_reservations.exists?
errors.add(:base, "You can only have one future reservation per company.")
end
end
end
解説
このカスタムバリデーションメソッドは、以下のステップで機能します:
-
早期リターン:
date
、customer_id
、またはcompany_id
が未設定の場合は、バリデーションをスキップします。 - 未来の予約の検索: 同一顧客、同一企業に対して、今日以降の日付で設定された未来の予約を検索します。
-
論理削除された予約の除外:
deleted_at
がnil
である、つまり論理削除されていない予約のみを対象にします。 - 自身の除外: 既存の予約を編集している場合は、自身を検索結果から除外します。
- エラーの追加: 上記条件に一致する予約が存在する場合は、エラーメッセージを追加します。
参考記事
ビューとコントローラー
このバリデーションは、モデルレベルで完結しているため、ビューやコントローラーに特別な変更は必要ありません。ただし、ユーザーに対して明確なフィードバックを提供するために、フォームにエラーメッセージを表示するロジックを確実に含めることが重要です。
まとめ
Railsにおけるカスタムバリデーションを利用することで、複雑なビジネスルールも柔軟に実装することができます。今回の事例では、顧客が未来に一つの企業に対して一つの予約しか持てないようにする制約を、簡潔に実現することができました。この方法は、アプリケーションの要件に応じて様々な制約条件に応用可能です。