Rails方式:在模型中设置之前格式化值?

时间:2010-12-03 19:40:26

标签: ruby-on-rails activerecord

我有用户输入的表单字段:

  • 百分比:50.5%
  • money:$144.99
  • 日期:Wednesday, Jan 12th, 2010

...

percentmoney类型属性与ActiveRecord一起保存为decimal个字段,日期为datetimedate个字段。

在javascript中转换格式很容易,理论上你可以将它们转换为activerecord可接受的格式onsubmit,但这不是一个合适的解决方案。

我想覆盖ActiveRecord中的访问器,所以当它们被设置时,它会将它们从任何字符串转换为适当的格式,但这也不是最好的。

我不想要的是必须通过一个单独的处理器对象运行它们,这在控制器中需要这样的东西:

def create
  # params == {:product => {:price => "$144.99", :date => "Wednesday, Jan 12, 2011", :percent => "12.9%"}}
  formatted_params = Product.format_params(params[:product])
  # format_params == {:product => {:price => 144.99, :date => Wed, 12 Jan 2011, :percent => 12.90}}
  @product = Product.new(format_params)
  @product.save
  # ...
end

我希望它完全透明。 ActiveRecord中的钩子在哪里,所以我可以用 Rails方式来做这个?

更新

我现在正在做这件事:https://gist.github.com/727494

class Product < ActiveRecord::Base
  format :price, :except => /\$/
end

product = Product.new(:price => "$199.99")
product.price #=> #<BigDecimal:10b001ef8,'0.19999E3',18(18)>

3 个答案:

答案 0 :(得分:31)

你可以覆盖setter或getter。

覆盖二传手:

class Product < ActiveRecord::Base
  def price=(price)
    self[:price] = price.to_s.gsub(/[^0-9\.]/, '')
  end
end

覆盖吸气剂:

class Product < ActiveRecord::Base
  def price
    self[:price].to_s.gsub(/[^0-9\.]/, ''))
  end
end

不同之处在于后一种方法仍然存储用户输入的任何内容,但检索格式化,而第一种方法存储格式化版本。

当您致电Product.new(...)update_attributes等等时,将使用这些方法

答案 1 :(得分:12)

您可以使用前验证挂钩来规范化您的参数,例如before_validation

class Product < ActiveRecord::Base

     before_validation :format_params


      .....


     def format_params
        self.price = price.gsub(/[^0-9\.]/, "")
        ....
     end

答案 2 :(得分:1)

使用monetize gem解析数字。

实施例

Monetize.parse(val).amount