Rails 3 кастомная валидация и musta - PullRequest
4 голосов
/ 19 декабря 2011

В эти дни я колеблюсь между Митрой и Рспеком.Я читал и играл немного с 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

И вот мой course_spec

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)"]

Не уверен, что я здесь не так делаю.Это мой пользовательский код проверки, который не является правильным, или мне нужно что-то настроить перед выполнением последнего утверждения, чтобы при тестировании end_date не указывать значение start_date?

В представлении проверки работают нормально.Я имею в виду, что получаю правильные ошибки проверки в зависимости от типа вводимых данных.Но я провалился.Я уже давно смотрю на это, но не могу понять, что именно я делаю не так.

Ответы [ 2 ]

3 голосов
/ 21 декабря 2011

Я думаю, вы можете решить эту проблему одним из двух способов:

Либо вам нужно поместить 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
0 голосов
/ 19 декабря 2011

@ nickgrim уже ответил на вопрос, но я хочу добавить комментарий. Смысл describe и it состоит в том, чтобы поощрять предложения, начинающиеся со слов «описать» и «это». В вашем примере у вас есть это:

it " end date should not be before course start date" do
  # ...

"это дата окончания ...." - это не предложение. Пожалуйста, напишите это как-то так:

it "validates that end date should be >= start date" do
...