Как проверить атрибут даты модели по определенному диапазону (оценивается во время выполнения) - PullRequest
7 голосов
/ 03 декабря 2009

У меня есть несколько моделей с атрибутом даты, и для каждой модели я хотел бы проверить эти даты по заданному диапазону. Базовым примером будет:

validates_inclusion_of  :dated_on, :in => Date.new(2000,1,1)..Date(2020,1,1)

В идеале я хотел бы оценить диапазон дат во время выполнения, используя подход, аналогичный named_scope, например:

validates_inclusion_of  :dated_on, :in => lambda {{ (Date.today - 2.years)..(Date.today + 2.years)}}

Вышесказанное, конечно, не работает, так как лучше всего достичь того же результата?

Ответы [ 7 ]

13 голосов
/ 16 февраля 2011

Вы можете использовать валидатор даты :

    validates :dated_on, :date => {:after => Proc.new { Time.now + 2.years },
                                   :before => Proc.new { Time.now - 2.years } }
7 голосов
/ 03 декабря 2009

Если валидация одинакова для каждого класса, ответ довольно прост: поместите метод валидации в модуль и смешайте его с каждой моделью, затем используйте validate, чтобы добавить валидацию:

# in lib/validates_dated_on_around_now
module ValidatesDatedOnAroundNow
  protected

  def validate_dated_around_now
    # make sure dated_on isn't more than five years in the past or future
    self.errors.add(:dated_on, "is not valid") unless ((5.years.ago)..(5.years.from_now)).include?(self.dated_on)
  end
end

class FirstModel
  include ValidatesDatedOnAroundNow
  validate :validate_dated_around_now
end

class SecondModel
  include ValidatesDatedOnAroundNow
  validate :validate_dated_around_now
end

Если вам нужны разные диапазоны для каждой модели, вы, вероятно, хотите что-то более похожее на это:

module ValidatesDateOnWithin
  def validates_dated_on_within(&range_lambda)
    validates_each :dated_on do |record, attr, value|
      range = range_lambda.call
      record.errors.add(attr_name, :inclusion, :value => value) unless range.include?(value)
    end
  end
end

class FirstModel
  extend ValidatesDatedOnWithin
  validates_dated_on_within { ((5.years.ago)..(5.years.from_now)) }
end

class SecondModel
  extend ValidatesDatedOnWithin
  validates_dated_on_within { ((2.years.ago)..(2.years.from_now)) }
end
3 голосов
/ 25 июня 2013

validates :future_date, inclusion: { in: ->(g){ (Date.tomorrow..Float::INFINITY) }

1 голос
/ 03 декабря 2009

Другое решение состоит в том, чтобы полагаться на тот факт, что для validates_inclusion_of требуется только объект :in, который отвечает на include?. Создайте оцененный диапазон с задержкой следующим образом:

class DelayedEvalRange
  def initialize(&range_block)
    @range_block = range_block
  end
  def include?(x)
    @range_block.call.include?(x)
  end
end

class FirstModel
  validates_inclusion_of :dated_on, :in => (DelayedEvalRange.new() { ((5.years.ago)..(5.years.from_now)) })
end
0 голосов
/ 29 февраля 2016

Самое простое и рабочее решение - использовать встроенную валидацию из Rails. Просто проверяет это так:

validates :dated_on, inclusion: { in: (Date.new(2000,1,1)..Date(2020,1,1)) }

если вам нужно подтвердить присутствие, просто добавьте еще одну проверку:

validates :occurred_at, presence: true, inclusion: { in: (Date.new(2000,1,1)..Date(2020,1,1)) }

Помните, что вы всегда можете использовать такие помощники, как 1.day.ago или 1.year.from_now для определения диапазонов.

0 голосов
/ 20 мая 2015

Самым простым решением для меня было:

validate :validate_dob

def validate_dob
  unless age_range.cover?(dob.present? && dob.to_date)
    errors.add(:dob, "must be between %s and %s" % age_range.minmax)
  end
end

Однако, если вы хотите удалить дубликаты, я предлагаю переместить его в свой собственный валидатор .

Ида, я хочу выполнения во время выполнения, потому что мой код будет выполняться через пару лет, и после того, как я больше года не развертывался, я, конечно, не хочу снова запускать проект.

0 голосов
/ 09 мая 2012

Спросите себя, нужно ли вам оценивать диапазон во время выполнения. Хороший разработчик не всегда идет на корректность, если цена сложная, imho.

Я хотел проверить, что дата была разумной, то есть через несколько лет. Неважно, будет ли это интервал в несколько лет сегодня или две недели назад, и мои серверные процессы вряд ли будут работать через несколько лет. В конце концов я решил, что более простое решение (просто прямое включение: in => разумный_датчик_страницы) предпочтительнее правильного, но более сложного решения.

Тем не менее, мне нравится решение Джеймса А. Розена с DelayedEvalRange. Если ваш диапазон составляет всего пару дней или правильность важна по какой-то другой причине, я бы согласился с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...