2010-12-03 58 views
5

我有表单域当用户在输入:Rails方式:在设置模型之前格式化值?

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

...

percentmoney类型属性保存为decimal字段s与ActiveRecord,并且日期是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 Way

更新

我只是做这个现在: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)> 
+1

有一个名为“attribute_normalizer”如果你在你的应用程序重新编辑该值,你需要让这个过程双向例如,无论过程中,您在执行哪些做这项工作 – 2012-11-29 22:38:56

回答

10

您可以使用验证之前钩正常化您的PARAMS如before_validation

class Product < ActiveRecord::Base 

    before_validation :format_params 


     ..... 


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

宝石before_validation中,您需要通过覆盖getter来取消,请参阅iain对此问题的回答。 – 2011-05-19 15:36:21

+1

假设price是数据库中的数字,如上所述,它将在类型转换后发生。在看到format_params之前,“1ab23cd45”的用户输入意味着to_f处理为1。经过漫长的一天,我现在知道应该是self.price = price_before_type_cast.gsub([/ [^ 0-9 \。] /,'')使用自动生成的* _before_type_cast访问器是一个至关重要的秘密。 – elc 2013-01-10 02:40:15

29

你可以重写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等,这些方法将被用来...