はじめに
Ruby on Rails で どちらか一方のカラムを入力必須にするバリデーションについて書きます。
具体的な例をあげると、ユーザーモデルのemail
とphone
、どちらか片方だけに必ず値が入るようにバリデーションします。両方に値が入っている場合もNGです。
要件に合わなかったバリデーション
ググって下記のようなバリデーションを見つけましたが、両方入力した場合にバリデーションを通ってしまうので、要件には合いません。
app/models/user.rb
class User < ApplicationRecord
# phoneが空ならば、emailを必須にする
validates :email, presence: true, unless: :phone?
# emailが空ならば、phoneを必須にする
validates :phone, presence: true, unless: :email?
end
User.create!(name: "たなか", email: "test@example.com", phone: "08011112222")
=> #<User id: 1, name: "たなか", email: "tanaka@example.com", phone: "08011112222", created_at: "2020-03-19 12:29:20", updated_at: "2020-03-19 12:29:20">
要件にあったバリデーション
要件を満たすために、次のカスタムバリデーションを作成しました。
app/models/user.rb
class User < ApplicationRecord
validate :required_either_email_or_phone
private
def required_either_email_or_phone
# 演算子 ^ で排他的論理和(XOR)にしています
# emailかphoneのどちらかの値があれば true
# email、phoneどちらも入力されている場合や入力されていない場合は false
return if email.present? ^ phone.present?
errors.add(:base, 'メールアドレスまたは電話番号のどちらか一方を入力してください')
end
end
User.create!(name: "たなか", email: "tanaka@example.com", phone: "08011112222")
# => ActiveRecord::RecordInvalid (バリデーションに失敗しました: emailまたはphoneのどちらか一方を入力してください)
User.create!(name: "たなか", email: nil, phone: nil)
# => ActiveRecord::RecordInvalid (バリデーションに失敗しました: emailまたはphoneのどちらか一方を入力してください)
User.create!(name: "たなか", email: "tanaka@example.com", phone: nil)
# => <User id: 2, name: "たなか", email: "tanaka@example.com", phone: nil, created_at: "2020-03-19 13:06:55", updated_at: "2020-03-19 13:06:55">
おわり
普段は論理和 ||
演算子 か論理積 &&
演算子 ばかりで、^
演算子は使わないので、上記のコードを思いつくまでに時間をかけてしまいました…!