Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Age calculation in Ruby

I'm trying to write a rails application but presently the display for the date of birth is shown like the normal date format, but I wouldl love to show in views the age instead

The method I have in controller is below and I have a column DOb in my database for date of birthL

def age
  @user = user
  now = Time.now.utc.to_date
  now.year - @user.dob.year - (@user.dob.to_date.change(:year => now.year) > now ? 1 : 0)
end

It shows like DOB: 23/5/2011, but I would like it to be age in years instead.

How do I also put a validator that checks if age is below 18 years?

like image 865
El nino Avatar asked Jul 08 '26 15:07

El nino


2 Answers

For the validator, you can use a custom method:

validate :over_18

def over_18
  if dob + 18.years >= Date.today
    errors.add(:dob, "can't be under 18")
  end
end
like image 186
Baldrick Avatar answered Jul 11 '26 15:07

Baldrick


I ran across this question and thought I'd post a more modern answer that takes advantage of Rails convenience method syntax and custom validators.

Custom Age Validator

This validator will take an options hash for the field name you'd like to validate and the minimum age requirement.

# 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

Example Usage

class User < ActiveRecord::Base
  validates_with AgeValidator, { min_age: 18, field: :dob }
end

User#age convenience method

And to calculate the user's age for display, you'll want to be careful to calculate around leap years.

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

And the spec!

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
like image 30
Jonathan Crawford Avatar answered Jul 11 '26 16:07

Jonathan Crawford



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!