代码之家  ›  专栏  ›  技术社区  ›  ZX12R

无法理解rails activerecord类型转换原因

  •  3
  • ZX12R  · 技术社区  · 14 年前

    假设我有如下迁移

    create_table :dummies do |t|
      t.decimal :the_dummy_number
    end 
    

    我实例化如下

    dummy = Dummy.new
    dummy.the_dummy_number = "a string"
    puts dummy.the_dummy_number
    

    上面的输出是

     0.0
    

    最大的问题如下。

    验证

    更新

     validate :is_dummy_number_valid, :the_dummy_number
     def is_dummy_number_valid
        read_attribute(:the_dummy_number).strip()
     end
    
    1 回复  |  直到 14 年前
        1
  •  3
  •   Steve Weet    14 年前

    这不能像您预期的那样工作的原因是BigDecimal的底层ruby实现在传递字符串时不会出错。

    考虑以下代码

    [ 'This is a string', '2is a string', '2.3 is also a string', 
      '   -3.3 is also a string'].each { |d| puts "#{d} = #{BigDecimal.new(d)}" }
    
    This is a string = 0.0
    2is a string = 2.0
    2.3 is also a string = 2.3
       -3.3 is also a string = -3.3
    

    所以BigDecimal扫描字符串,并将字符串开头可能是十进制的任何内容赋给它的值。

    如果你把模特摆成这样

    class Dummy < ActiveRecord::Base
    
       validates_numericality_of :the_dummy_number
    
    end
    

    那么验证就可以了

    >> d=Dummy.new(:the_dummy_number => 'This is a string')
    => #<Dummy id: nil, the_dummy_number: #<BigDecimal:5b9230,'0.0',4(4)>, created_at: nil, updated_at: nil>
    
    >> puts d.the_dummy_number
    0.0
    => nil
    >> d.valid?
    => false
    
    >> d.errors
    => #<ActiveRecord::Errors:0x5af6b8 @errors=#<OrderedHash
      {"the_dummy_number"=>[#<ActiveRecord::Error:0x5ae114 
       @message=:not_a_number, @options={:value=>"This is a string"}
    

    这是因为validates\u numericability\u宏使用raw\u value方法在值被类型转换并赋给内部十进制值之前获取该值。