database - 即使自定义验证失败 Rails 3 也会保存记录

标签 database ruby-on-rails-3 validation

我正在使用 Rails 3.0.5,我为我的模型进行了自定义验证,当我创建或更新容器记录时,验证有效地执行并在必要时添加错误,但记录仍然存在保存在数据库中。

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

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

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

最佳答案

我认为您很接近,但您一直在阅读片段而不是教程或文档。如果您引用 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 ,他们甚至建议您在类/模型中定义自定义验证器类:

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

干杯!

关于database - 即使自定义验证失败 Rails 3 也会保存记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5463442/

相关文章:

ruby - 在 Rails 应用程序中导入 CSV 时忽略具有空白值的行

mysql - 从位置模型获取城市列表以及每个城市存在多少个位置

mysql - 如何使用表中的现有变量在表中创建递增变量

sql - PostgresQL 查询计算一天内的时间间隔

java - 从特定行数获取数据

ruby-on-rails - 是否可以更改 Rails 项目中的文件夹结构?

ASP.NET MVC 3 : programmatically add DataAnnotation (RequiredAttribute) to view model

java - Hibernate validator 使用 @Length 注释和不使用 @NotEmpty 注释来验证字段

c# - 如何检查用户输入的 MaskedTextBox 是否为空?

java - self 管理单调递增关键 OR 系统的时间戳