Подтвердить что ты не робот

Проверка свойства модели больше, чем другая

Во-первых, позвольте мне сказать, что я чрезвычайно новичок в Rails (играли с ним время или два, но заставляли себя писать полный проект с ним сейчас, начатый вчера).

Теперь я пытаюсь проверить, что свойство модели (терминология?) больше, чем другое. Это оказалось идеальным экземпляром для validates_numericality_of с опцией greater_than, но, увы, это вызывает ошибку, сообщающую мне greater_than expects a number, not a symbol. Если я попытаюсь отобразить этот символ .to_f, я получаю ошибку undefined method.

Вот что я в итоге сделал, и мне любопытно, есть ли лучший способ. Это просто простая система управления релизами проекта, у нас есть только основные/незначительные релизы (одноточечные), поэтому float почувствовал, что это правильное решение здесь.

class Project < ActiveRecord::Base
    validates_numericality_of :current_release
    validates_numericality_of :next_release
    validate :next_release_is_greater

    def next_release_is_greater
        errors.add_to_base("Next release must be greater than current release") unless next_release.to_f > current_release.to_f
    end
end

Это работает - он передает соответствующий unit test (ниже для вашего удовольствия просмотра), мне просто интересно, есть ли более простой способ - я мог бы попробовать иначе.

Соответствующий unit test:

# Fixture data:
#   PALS:
#     name: PALS
#     description: This is the PALS project
#     current_release: 1.0
#     next_release: 2.0
#     project_category: 1
#     user: 1
def test_release_is_future
    project = Project.first(:conditions => {:name => 'PALS'})
    project.current_release = 10.0
    assert !project.save

    project.current_release = 1.0
    assert project.save
end
4b9b3361

Ответ 1

Как вы заметили, единственный способ - использовать пользовательский валидатор. Опция: more_than должна быть целым числом. Следующий код не будет работать, поскольку текущая и следующая версия доступны только на уровне экземпляра.

class Project < ActiveRecord::Base
  validates_numericality_of :current_release
  validates_numericality_of :next_release, :greater_than => :current_release
end

Цель параметра greater_than - проверить значение для статической константы или другого метода класса.

Итак, не возражайте и продолжайте свой собственный валидатор.:)

Ответ 2

validates_numericality_of принимает большой список опций, и некоторые из них могут быть снабжены проком или символом (это означает, что вы можете в принципе передать атрибут или весь метод).

для проверки численного значения свойства выше другого значения:

class Project < ActiveRecord::Base
  validates_numericality_of :current_release, less_than: ->(project) { project.next_release }

  validates_numericality_of :next_release, 
    greater_than: Proc.new { project.current_release }
end

Чтобы уточнить, любой из этих параметров может принимать proc или символ:

  • :greater_than
  • :greater_than_or_equal_to
  • :equal_to :less_than
  • :less_than_or_equal_to

validates_numericality docs: http://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of

с использованием procs с проверками: http://guides.rubyonrails.org/active_record_validations.html#using-a-proc-with-if-and-unless

Ответ 3

С Rails 3.2 вы можете проверять два поля друг против друга на лету, передавая в proc.

validates_numericality_of :next_release, :greater_than => Proc.new {|project| project.current_release }

Ответ 4

Чтобы наилучшим образом выполнить пользовательскую проверку, возможно, вам стоит взглянуть на что-то наподобие factory_girl в качестве замены светильников (которые, по-видимому, вы используете):

http://github.com/thoughtbot/factory_girl

Ваш unit test будет выглядеть следующим образом:

def test_...
    Factory.create(:project, :current_release => 10.0)
    assert !Factory.build(:project, :current_release => 1.0).valid?
end