私はこの質問に出くわし、Railsの便利なメソッド構文とカスタムバリデーターを利用したより現代的な回答を投稿したいと思いました。
カスタム年齢バリデーター
このバリデーターは、検証するフィールド名と最低年齢要件のオプションハッシュを取得します。
# Include somewhere such as the top of user.rb to make sure it gets loaded by Rails.
class AgeValidator < ActiveModel::Validator
def initialize(options)
super
@field = options[:field] || :birthday
@min_age = options[:min_age] || 18
@allow_nil = options[:allow_nil] || false
end
def validate(record)
date = record.send(@field)
return if date.nil? || @allow_nil
unless date <= @min_age.years.ago.to_date
record.errors[@field] << "must be over #{@min_age} years ago."
end
end
end
使用例
class User < ActiveRecord::Base
validates_with AgeValidator, { min_age: 18, field: :dob }
end
User#age
便利な方法
また、表示するユーザーの年齢を計算するには、うるう年の前後を慎重に計算する必要があります。
class User < ActiveRecord::Base
def age
return nil unless dob.present?
# We use Time.current because each user might be viewing from a
# different location hours before or after their birthday.
today = Time.current.to_date
# If we haven't gotten to their birthday yet this year.
# We use this method of calculation to catch leapyear issues as
# Ruby's Date class is aware of valid dates.
if today.month < dob.month || (today.month == dob.month && dob.day > today.day)
today.year - dob.year - 1
else
today.year - dob.year
end
end
end
そしてスペック!
require 'rails_helper'
describe User do
describe :age do
let(:user) { subject.new(dob: 30.years.ago) }
it "has the proper age" do
expect(user.age).to eql(30)
user.birthday += 1.day
expect(user.age).to eql(29)
end
end
end