Rails 3 кастомная валидация и musta
Я болтаюсь между собой и Rspec в эти дни. Я читал и играл немного с RSpec, но не так уж с Ifa. Я считаю, что утверждения Оданы в одной строке легче читать, а тест выглядит чище. Но когда я не могу понять, как написать конкретное утверждение в Долже, я переключаюсь на RSpec. Не очень доволен, хотя.
Итак, вот что я сделал сегодня. Я написал несколько пользовательских проверок для моей модели Course
, Курс имеет start_date
и end_date.
Есть несколько правил вокруг этого.
start_date
а такжеend_date
оба являются обязательнымиstart_date
не может быть позже, чем сегодняend_date
не может быть доstart_date
Я знаю, что есть несколько камней, которые могли бы сделать это для меня. Но потому что я новичок, я подумал, что было бы неплохо сделать это самому и учиться на ходу.
Так вот как выглядит моя модель
class Course < ActiveRecord::Base
belongs_to :category
has_many :batches, :dependent => :destroy
accepts_nested_attributes_for :batches, :reject_if => lambda {|a| a[:code].blank?}, :allow_destroy => true
has_and_belongs_to_many :students, :uniq => true
validates_presence_of :name, :course_code, :total_seats
validates_uniqueness_of :category_id, :scope => [:name, :course_code]
validates :start_date, :presence => true, :course_start_date=>true
validates :end_date, :presence => true, :course_end_date=>true
end
Мои пользовательские проверки следующие
class CourseEndDateValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
if object.errors[attribute].blank? && object.errors[:start_date].blank?
if value < object.start_date
object.errors[attribute] << "cannot be later than start date"
end
end
end
end
class CourseStartDateValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
if object.errors[attribute].blank?
if value < DateTime.now.to_date
object.errors[attribute] << "cannot be later than today"
end
end
end
end
И вот мой курс_спек
require 'spec_helper'require 'date'
describe Course do
context 'validations' do
it { should validate_presence_of(:name)}
it { should validate_presence_of(:course_code)}
it { should validate_presence_of(:start_date)}
it { should validate_presence_of(:end_date)}
it { should validate_presence_of(:total_seats)}
date = DateTime.now.to_date
it { should allow_value(date).for(:start_date) }
it { should_not allow_value(date - 10 ).for(:start_date) }
it {should allow_value(date + 10).for(:end_date)}
end
context 'associations' do
it { should belong_to(:category)}
it { should have_many(:batches).dependent(:destroy)}
it { should have_and_belong_to_many(:students) }
end
it " end date should not be before course start date" do
course = FactoryGirl.build(:course, :end_date=>'2011-12-10')
course.should be_invalid
end
end
Теперь, прежде чем я написал последний блок "it" с использованием Rspec, у меня было что-то подобное в контексте проверки
context 'validations' do
it { should validate_presence_of(:name)}
it { should validate_presence_of(:course_code)}
it { should validate_presence_of(:start_date)}
it { should validate_presence_of(:end_date)}
it { should validate_presence_of(:total_seats)}
date = DateTime.now.to_date
it { should allow_value(date).for(:start_date) }
it { should_not allow_value(date - 10 ).for(:start_date) }
it { should allow_value(date + 10).for(:end_date)}
it { should_not allow_value(date - 10).for(:end_date)} # <-------------------
end
И я получил следующий сбой
Failures:
1) Course validations
Failure/Error: it { should_not allow_value(date - 10).for(:end_date)}
Expected errors when end_date is set to Fri, 9 Dec 2011, got errors: ["name can't be blank (nil)", "course_code can't be blank (nil)", "total_seats can't be blank (nil)", "start_date can't be blank (nil)"]
Я не уверен, что я делаю не так здесь. Это мой пользовательский код проверки, который не является правильным, или мне нужно что-то настроить перед тем, как запустить последнее утверждение, чтобы start_date не равнялся nil при тестировании end_date?
Проверки работают хорошо в представлении. Я имею в виду, что получаю правильные ошибки проверки в зависимости от типа вводимых данных. Но я провалился. Я уже давно смотрю на это, но не могу понять, что именно я делаю не так.
2 ответа
Я думаю, что вы можете решить это одним из двух способов:
Либо вам нужно разместить вас date = DateTime.now.to_date
в before(:each)
блок.
context 'validations' do
before(:each) { date = DateTime.now.to_date }
it { should allow_value(date).for(:start_date) }
it { should_not allow_value(date - 10 ).for(:start_date) }
it { should allow_value(date + 10).for(:end_date)}
it { should_not allow_value(date - 10).for(:end_date)}
end
Или вы могли бы использовать помощников даты рельсов.
context 'validations' do
it { should allow_value(Date.today).for(:start_date) }
it { should_not allow_value(10.days.ago).for(:start_date) }
it { should allow_value(10.days.from_now).for(:end_date)}
it { should_not allow_value(10.days.ago).for(:end_date)}
end
@nickgrim уже ответил на вопрос, но я хочу добавить комментарий. Точка describe
а также it
это поощрять предложения, которые начинаются со слов "описать" и "это". В вашем примере у вас есть это:
it " end date should not be before course start date" do
# ...
"это дата окончания...." не является предложением. Пожалуйста, напишите это как-то так:
it "validates that end date should be >= start date" do