2011-03-28 53 views
3

我正在使用rails 3.0.5,并且为我的模型进行了自定义验证,当我创建或更新容器记录时,验证被有效执行并添加错误时它必须,但记录仍然保存在数据库中。即使自定义验证失败,记录也会保存Rails 3

我测试了自定义验证方法的每一步,并且正常工作。

这里是我的模型和自定义的验证:

class Container < ActiveRecord::Base 
    include Comparable 
    belongs_to :booking 

    validates :booking, presence: true 
    validates :kind, presence: true 
    validates :dimension, presence: true, numericality: { only_integer: true } 
    validates :retirement_location, presence: true 
    validates :amount, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 1 } 
    validate :uniqueness_of_single_fields 

    scope :group, lambda {|k,d| where('kind = ? and dimension = ?',k,d) } 

    def self.to_hash 
    { 
     "kind" => self.kind.to_s, 
     "dimension" => self.dimension.to_s, 
     "retirement_location" => self.retirement_location.to_s 
    } 
    end 

    def uniqueness_of_single_fields 
    similar_containers = Container.joins(:booking).where('bookings.requirement_id = ? and containers.id != ?', booking.requirement.id, id) 
    similar_containers = similar_containers.where(assigned_unit: assigned_unit, assigned_seal: assigned_seal) 

    unless similar_containers.empty? 
     errors.add(:base, "esa unidad y sello ya han sido asignados") 
    end 
    end 

    def <=>(other) 
    result = kind <=> other.kind 
    result == 0 ? dimension <=> other.dimension : result 
    end 
end 

附:我检查了前面的问题,但没有那么有这个问题的答案

我做了一个测试的RSpec尝试这种

require 'spec_helper' 

describe Container do 
    it 'should have a uniq combination assigned unit and seal for in a requirement' do 
    requirement1 = Factory(:requirement, reference: 'abc123') 
    requirement2 = Factory(:requirement, reference: 'qwerty') 

     booking1 = Factory(:booking, reference: 'FOOBAR123', requirement: requirement1) 
    booking2 = Factory(:booking, reference: 'FOOBAR456', requirement: requirement1) 
    booking3 = Factory(:booking, reference: 'FOOBAR789', requirement: requirement2) 

    container1 = Factory(:container, assigned_unit: 'foo1', assigned_seal: 'bar1', booking: booking1) 
    container2 = Factory.build(:container, assigned_unit: 'foo1', assigned_seal: 'bar1', booking: booking2) 
    container3 = Factory(:container, assigned_unit: 'foo1', assigned_seal: 'bar1', booking: booking3) 

    container1.should be_valid 
    container3.should be_valid 

    puts container2.errors 
    container2.save 
    puts container2.inspect 
    container2.should_not be_valid 
    puts container2.errors.inspect 
    container2.errors[:base].first.should == "esa unidad y sello ya han sido asignados" 

    c = Requirement.new(client: 'foo') 
    c.save 
    puts c.errors 
    puts c.inspect 
    end 
end 

,输出是:(它通过时应该失败)

{} 
#<Container id: 6, kind: "dry", dimension: 20, retirement_location: "sitrans", booking_id: 5, created_at: "2011-03-28 22:31:13", updated_at: "2011-03-28 22:31:13", load: "wine 2", assigned_unit: "foo1", assigned_seal: "bar1", temp_celsius: nil, temp_fahrenheit: nil, vent_percentage: nil, vent_cfm: nil, generator: nil, amount: 1> 
{:base=>["esa unidad y sello ya han sido asignados"]} 
{:service=>["Debe elegir un tipo de servicio"], :shipping_company=>["Debe haber una naviera relacionada con esta orden de servicio"]} 
#<Requirement id: nil, client: "foo", service_id: nil, realization: nil, hour: nil, shipping_company_id: nil, description: nil, created_at: nil, updated_at: nil, reference: nil, state: "new"> 
. 

Finished in 0.45293 seconds 
1 example, 0 failures 
+0

当您调用'model.save!'时出现任何错误? – Zabba 2011-03-28 20:58:08

+0

什么也没有发生 – fespinozacast 2011-03-28 22:29:10

+0

为什么'container2 = Factory.build('而不是'container2 = Factory('? – Zabba 2011-03-28 23:52:30

回答

1

我认为你很接近,但你一直在阅读片段而不是教程或文档。如果你引用Railscast Episode On Rails3 Validations,那么你会看到他们建议定义你自己的自定义验证器子类,而不是将另一个函数粘贴到你的模型上。

你可能会说抽象是不需要的,只是因为它是“更合适的”或其他的?然后检查了API doc for Validations

在这里,他们说:“一个最小的实施”是这样的:

class Person 
    include ActiveModel::Validations 

    attr_accessor :first_name, :last_name 

    validates_each :first_name, :last_name do |record, attr, value| 
    record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z 
    end 
end 

class Person 
    include ActiveModel::Validations 

    validates :instance_validations 

    def instance_validations 
    validates_with MyValidator 
    end 
end 

最重要的是API entry for the validates method,他们甚至建议你定义一个定制Validator class in your class/model:

class Film 
    include ActiveModel::Validations 

    class TitleValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
     record.errors[attribute] << "must start with 'the'" unless value =~ /\Athe/i 
    end 
    end 

    validates :name, :title => true 
end 

干杯!