【问题标题】:Rails / ActiveRecord: field normalizationRails / ActiveRecord:字段标准化
【发布时间】:2009-05-19 16:44:53
【问题描述】:

我正在尝试从模型中的字段中删除逗号。我希望用户输入一个数字,即 10,000,并且该数字应作为 10000 存储在数据库中。我希望我可以进行一些模型端规范化以删除逗号。我不想依赖视图或控制器来正确格式化我的数据。

我试过了:

before_validation :normalize

def normalize 
 self['thenumber'] = self['thenumber'].to_s.gsub(',','')
end

没用。

【问题讨论】:

    标签: ruby-on-rails activerecord model


    【解决方案1】:

    http://github.com/mdeering/attribute_normalizer 看起来是解决这个常见问题的有希望的解决方案。以下是主页中的一些示例:

      # By default it will strip leading and trailing whitespace
      # and set to nil if blank.
      normalize_attributes :author, :publisher
    
      # Using one of our predefined normalizers.
      normalize_attribute  :price, :with => :currency
    
      # You can also define your normalization block inline.
      normalize_attribute :title do |value|
        value.is_a?(String) ? value.titleize.strip : value
      end
    

    所以在你的情况下,你可能会做这样的事情:

      normalize_attribute :title do |value|
        value.to_s.gsub(',', '')
      end
    

    【讨论】:

      【解决方案2】:

      我认为你做得对。此测试通过:

      test "should remove commas from thenumber" do
        f = Foo.new(:thenumber => "10,000")
        f.save
        f = Foo.find(f.id)
        assert f.thenumber == "10000"    
      end
      

      我使用了你的代码。

       class Foo < ActiveRecord::Base
        before_validation :normalize
      
        def normalize 
          self['thenumber'] = self['thenumber'].to_s.gsub(',','')
        end
      
       end
      

      现在,我的架构设置为数字是字符串,而不是整数。

      Started
      .
      Finished in 0.049666 seconds.
      
      1 tests, 1 assertions, 0 failures, 0 errors
      

      如果你想将它作为整数存储在数据库中,那么你肯定需要覆盖 setter:

       def thenumber=(value)
         self['thenumber'] = value.to_s.gsub(',','').to_i
       end
      

      如果你按照自己的方式使用整数列,它会被 AR 截断......

      >> f.thenumber = "10,000"
      => "10,000"
      >> f.thenumber
      => 10
      

      对于 Ruby 和整数来说,这是一个鲜为人知的事情......它通过截断不再是整数的任何内容来自动转换。

      irb(main):004:0> i = "155-brian-hogan".to_i
      => 155
      

      对于诸如此类的事情可能很酷

      /users/155-brian-hogan
      
      @user = User.find_by_id(params[:id])
      

      但对于你正在做的事情来说并不那么酷。

      所以要么将 col 更改为字符串并使用过滤器,要么更改 setter :)

      祝你好运!

      【讨论】:

      • 感谢您非常详细的回复!
      【解决方案3】:

      这样做的问题是,有一段时间,对象中会存在非规范化的东西;如果你有代码在东西被规范化之前对属性起作用,那么这将是一个问题。

      你可以定义一个 setter:

      def thenumber=(value)
        # normalise stuff here, call write_attribute
      end
      

      不幸的是,我认为很多 Rails 表单的东西都是直接写属性的,这也是我不倾向于使用它的原因之一。

      或者您可以在传递控制器中的参数之前对其进行规范化。

      【讨论】:

      • 是的,我已经辞职,在控制器中的参数进入 AR 之前对其进行规范化......
      【解决方案4】:

      ruby 是否允许您在 .和 [''] ? 我不知道,我稍后会尝试,但我认为你应该使用。

      self.thenumber = self.thenumber.to_s.gsub(',','')
      

      【讨论】:

        【解决方案5】:

        您应该从 before_validation 方法中返回 true,否则如果分配给 self['thenumber'] 的表达式最终为 nil 或 false,则数据将不会被保存,根据 Rails 文档:

        如果 before_* 回调返回 false, 所有后来的回调和 相关操作被取消。

        表面上,您尝试在这里进行规范化,然后使用 Rails 验证检查规范化的结果,这将决定 nil/false/blank 是否正常。

        before_validation :normalize
        
        def normalize 
          self['thenumber'] = self['thenumber'].to_s.gsub(',','')
          return true
        end
        

        【讨论】:

        • 只是添加我希望我早先在这里看到的注释... before_validation 发生在类型转换之后,所以如果数字是数字类型并且您正在执行类似剥离 $ 和 的操作,则您需要 self ['thenumber'] = thenumber_before_type_cast.to_s.gsub(...) before_type_cast 版本是自动生成的,如果已经是数字,需要to_s。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-15
        • 1970-01-01
        • 1970-01-01
        • 2012-03-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多