【问题标题】:Why is :if not being recognised by ActiveRecord validations?为什么 :if 未被 ActiveRecord 验证识别?
【发布时间】:2010-07-01 17:55:17
【问题描述】:

我遇到了一个问题,即 ActiveRecord 验证中的 :if 子句没有得到遵守。

我的模型有一个 ip_port 属性,我正在验证它是否存在、数字且在一定范围内。我试图确保每个条件只产生一个错误。我不希望空属性导致向用户显示三条消息,说明它不存在、必需且不是数字的情况。

这是我的模型

class Arc < ActiveRecord::Base
  attr_accessible :ip_port

  validates_presence_of :ip_port
  validates_numericality_of :ip_port, :allow_blank => true
  validates_inclusion_of :ip_port, :in => 1025..65535, :allow_blank => true, 
     :if => Proc.new {|arc| arc.ip_port.to_s.match(/^\d+$/) }
end

这是我的模型规格及其结果。

describe Arc do
  it "should be valid with valid attributes" do
    Arc.new(:ip_port => 1200).should be_valid
  end
  it "should be invalid with a non-numberic port" do
    Arc.new(:ip_port => "test").should be_invalid
  end
  it "should be invalid with a missing port" do
    Arc.new(:ip_port => nil).should be_invalid
  end
  it "should have one error with a missing port" do
    a = Arc.new(:ip_port => nil)
    a.should be_invalid
    a.should have(1).errors_on(:ip_port)
  end
  it "should have one error with a non-numeric port" do
    a = Arc.new(:ip_port => "test")
    a.should be_invalid
    a.should have(1).errors_on(:ip_port)
  end
  it "should have one error with a numeric port outside the range" do
    a = Arc.new(:ip_port => 999)
    a.should be_invalid
    a.should have(1).errors_on(:ip_port)
  end
end
弧 - 应该对有效属性有效 - 对于非数字端口应该是无效的 - 缺少端口应该是无效的 - 应该有一个缺少端口的错误 - 非数字端口应该有一个错误 (FAILED - 1) - 数值端口超出范围应该有一个错误 1) 'Arc 应该有一个非数字端口错误' FAILED 预期 1 个错误:ip_port,得到 2 个 ./spec/models/arc_spec.rb:21: 在 0.108245 秒内完成

我的问题是,当 :if 子句应该阻止调用 validates_inclusion 时,为什么我会收到两个非数字 ip_port 错误。

这是 OS/X 10.6.3 上带有 Ruby 1.8.7 的 Rails 2.3.5

【问题讨论】:

    标签: ruby-on-rails ruby activerecord


    【解决方案1】:

    在沉思漫步的同时,我解决了自己的问题。

    问题在于,为了验证范围内的包含,它将提供的值转换为 int,然后检查是否包含。所以对于一个非数字值,我会得到一个 :not_a_number 和一个 :inclusion 错误。

    答案是修改 :if 子句以使用类型转换之前的值,因此我的 validates_inclusion_of 方法变为

    validates_inclusion_of :ip_port, :in => 1025..65535, :allow_blank => true, 
      :if => Proc.new {|arc| arc.ip_port_before_type_cast.to_s.match(/^\d+$/) }
    

    然后,这三个条件中的每一个都会给我一个错误。

    【讨论】:

    • 如果你使用类型转换之前的值,你还需要to_s吗? (不是说你绝对错了——只是问我自己的无知)
    • @Chris。是的你是。如果为 ip_port 属性分配了一个整数,则验证将失败,因为匹配将在 Fixnum 上失败。
    • 啊,当然,因为这是写入数据库。继续探索我的知识范围 - 为什么在您使用 arc.ip_port 时会触发数值验证?
    • @chris。我想我没有很好地解释自己。如果我实例化一个新模型然后调用model.ip_port = 3000,则没有 to_s。当我尝试验证模型时,validates_inclusion 宏将调用 Proc,然后它将执行 3000.match(...) 这将失败,因为 3000 是 Fixnum 的实例,它没有匹配方法。
    • 我想可能是我不清楚......基本上,我不完全理解你原来问题的原因。为什么在原始案例中会出现两个错误?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-20
    相关资源
    最近更新 更多