These days takes place between Shoulda and Rspec. I read and played around honest with RSpec, but not so much with Shoulda. I find that a single line statement is easier to read and the test looks cleaner. But when I cannot figure out how to write a specific statement in Shoulda, I will switch to RSpec. However, this is not very pleasing.
So here is what I did today. I wrote some custom checks for my Course model. The course has start_date and end_date. . It has a few rules.
start_date and end_date are requiredstart_date cannot be later than todayend_date cannot be before start_date
I know that there are several stones that could do this for me. But since I'm new, I thought it might be a good idea to do it myself and learn when I go.
So my model looks like
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
My user checks look like this
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
And my next course_special
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
Now, before I wrote the last "it" block using Rspec, I had something similar in the context of my validation.
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)}
And I got the next crash
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)"]
Not sure what I'm doing wrong here. Is my custom validation code incorrect or do I need to configure something before I run the last statement so that start_date is not null when testing end_date?
Checks work great in a view. I mean, I get the correct validation errors depending on the type of data that I entered. But the test fails. I looked at this for a while, but I canβt understand what exactly I am doing wrong.