Ruby on rails Ruby中的年龄计算

Ruby on rails Ruby中的年龄计算,ruby-on-rails,ruby,datetime,Ruby On Rails,Ruby,Datetime,我正在尝试编写一个rails应用程序,但目前显示出生日期的方式与正常的日期格式类似,但我更喜欢在视图中显示年龄 我在控制器中的方法如下所示,我的数据库中有一列DOb作为出生日期 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 它显示的像是DO

我正在尝试编写一个rails应用程序,但目前显示出生日期的方式与正常的日期格式类似,但我更喜欢在视图中显示年龄

我在控制器中的方法如下所示,我的数据库中有一列DOb作为出生日期

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
它显示的像是DOB:23/5/2011,但我希望它是以年为单位的


如何设置验证器来检查年龄是否低于18岁?

对于验证器,您可以使用:


这里有几个不同的问题

  • 年龄计算在哪里

    年龄计算应为辅助方法或模型方法。我一直将其作为一种模型方法,但最近看到了在decorator甚至helper方法中使用这些显示元素的优势。在您的情况下,从将其放入模型开始,然后从模型开始:

    def age
        now = Time.now.utc.to_date
        now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
    end
    
  • 您如何确认此人已超过18岁

    如果某人未满18岁,您是否真的限制他们保存到数据库中?还是你限制了他们的观看能力

    def is_over_18?
        age >= 18
    end
    

  • 这就为每个验证器编写了一个自定义代码,或者使用了一个Proc,但我真的怀疑用这种方式进行验证的决定。

    在计算年龄时,你应该小心。这里有一个正确的方法:

    def age(as_at = Time.now)
      as_at = as_at.utc.to_date if as_at.respond_to?(:utc)
      as_at.year - dob.year - ((as_at.month > dob.month || (as_at.month == dob.month && as_at.day >= dob.day)) ? 0 : 1)
    end
    
    之后,根据@Baldrick:

    validate :check_over_18
    
    def check_over_18
      errors.add(:dob, "can't be under 18") if age < 18
    end
    
    validate:check_over_18
    def检查超过18
    错误。如果年龄小于18岁,则添加(:dob,“不能低于18”)
    结束
    
    我也不得不处理这件事,但已经处理了好几个月了。变得太复杂了。我能想到的最简单的方法是:

    def month_number(today = Date.today)
      n = 0
      while (dob >> n+1) <= today
        n += 1
      end
      n
    end
    
    def月号(今天=日期。今天)
    n=0
    
    而(dob>>n+1)>n+12)要查找年龄,您可以使用gem


    我遇到了这个问题,我想我应该发布一个更现代的答案,利用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
    
    还有规格!
    我不明白年龄的问题;张贴你观点的相关代码以澄清。不精确到当天<代码>((日期。新(2000年)。到时间-日期。新(1982年)。到时间)/1.5年)。楼层=>17
    @Marc AndréLafortune我想这与闰年有关吧?还是别的什么?@Marc AndréLafortune更新了我的答案。谢谢你指出这一点。我想的更多的是这个方法属于哪里,而不是这个方法本身。这应该是一个更彻底的答案。我认为应该是
    ,否则18岁的生日就不算了。
    时间。当前。截止日期
    日期。今天
    更好。
    日期。如果你碰巧将应用程序的时区设置为系统时间以外的某个时间,今天
    将无法正常工作。见本讨论:
    def age(today = Date.today)
      n = 0
      while (dob >> n+12) <= today
        n += 1
      end
      n
    end
    
    age = AdroitAge.find_age("23/01/1990")
    => 23
    
    # 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
    
    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