Проверка свойства модели больше, чем другая
Во-первых, позвольте мне сказать, что я чрезвычайно новичок в 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
Ответы
Ответ 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