ruby-on-rails - Rails 3 自定义验证和 shoulda

标签 ruby-on-rails validation rspec2 shoulda

这些天我在 Shoulda 和 Rspec 之间摇摆不定。我已经阅读并使用了相当多的 RSpec,但与 Shoulda 相比并没有那么多。我发现 Shoulda 的单行断言更易于阅读,并且测试看起来更清晰。但是当我不知道如何在 Shoulda 中编写特定断言时,我切换到 RSpec。不过也不是很开心。

所以这就是我今天所做的。我为我的模型编写了一些自定义验证 Course .类(class)有 start_date和一个 end_date.围绕它有一些规则。

  • start_dateend_date都是强制性的
  • start_date不能晚于今天
  • end_date不能在 start_date 之前

  • 我知道那里有一些安静的 gem 可以为我做到这一点。但是因为我是新手,所以我认为自己做并边走边学可能是个好主意。

    所以这就是我的模型的样子
    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
    

    现在,在我使用 Rspec 编写最后一个“it”块之前,我的验证上下文中有类似的内容
    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 不为零?

    验证在 View 中工作正常。我的意思是我得到正确的验证错误取决于我输入的数据类型。但是我测试失败了。我已经研究了一段时间,但无法弄清楚我到底做错了什么。

    最佳答案

    我认为您可以通过以下两种方式之一解决此问题:

    要么你需要放置你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
    

    或者您可以使用 rails 日期助手。
    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
    

    关于ruby-on-rails - Rails 3 自定义验证和 shoulda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8558369/

    相关文章:

    ruby - 是否可以在 RSpec 中使用参数化规范?

    ruby-on-rails - rails 事件记录选择

    ruby-on-rails - 如何在 Ruby on Rails ActiveRecord 迁移中处理过长的索引名称?

    javascript - jQuery 在运行时删除 validationEngine

    ruby-on-rails - Spork 在我的 Rails 应用程序中导致未定义的方法错误?

    ruby-on-rails-3 - 如何配置 capybara 与Poltergeist一起使用?

    html - 如何添加内嵌背景图片?

    ruby-on-rails - 如何获取相关模型数据?

    java - 使用用户输入搜索对象数组,验证输入

    java - 无法将时间字符串解析为指定格式