Ruby on rails 在rails 3中保存到数据库之前如何格式化值

Ruby on rails 在rails 3中保存到数据库之前如何格式化值,ruby-on-rails,ruby,ruby-on-rails-3,activerecord,Ruby On Rails,Ruby,Ruby On Rails 3,Activerecord,我有一个利润领域的用户模型。利润字段是十进制(11,0)类型。我在表单上有一个隐藏的输入,允许用户输入大约1000美元。我想格式化该值,并从中删除除数字以外的所有内容,以便保存1000个。以下是我到目前为止的情况: class User < ActiveRecord::Base before_save :format_values private def format_values self.profit.to_s.delete!('^0-9') unless se

我有一个利润领域的用户模型。利润字段是十进制(11,0)类型。我在表单上有一个隐藏的输入,允许用户输入大约1000美元。我想格式化该值,并从中删除除数字以外的所有内容,以便保存1000个。以下是我到目前为止的情况:

class User < ActiveRecord::Base
  before_save :format_values

  private

  def format_values
    self.profit.to_s.delete!('^0-9') unless self.profit.nil?
  end
end
class用户
但它一直在数据库中保存0。看起来它在我的格式化函数之前将其转换为十进制。

尝试以下操作:

  def format_values
    self.profit.to_d!
  end
def profit=(new_profit)
  self[:profit] = new_profit.gsub(/[^0-9]/, '')
end

我建议您为这个特定的实例变量@profit编写自定义setter:

class User
  attr_accessor :profit

  def profit= value    
    @profit = value.gsub(/\D/,'')
  end
end

u = User.new
u.profit = "$1,000"
p u.profit # => "1000"

我建议精确地使用数字的rails助手。下面是一些代码

一般示例:

number_with_precision(111.2345, :precision => 1, :significant => true)     # => 100
Rails代码示例:

def profit=(new_profit)
  number_with_precision(self[:profit], :precision => 1, :significant => true)
end
class用户
首先,这:

def format_values
  self.profit.to_s.delete!('^0-9') unless self.profit.nil?
end
与此基本相同:

def format_values
    return if(self.profit.nil?)
    p = self.profit
    s = p.to_s
    s.delete!('^0-9')
end
因此,没有理由期望您的
格式\u值
方法对
自利
产生任何影响

当然,您可以更改
格式\u值
以将处理后的字符串分配给
self.price
,但这不会有帮助,因为您的清理逻辑位于错误的位置,它将在
'$1000'
变为零后执行

当您为属性赋值时,ActiveRecord将在此过程中应用一些类型转换。当您尝试将
'$1000'
转换为数字时会发生什么情况?你当然得零分。如果您在控制台中玩游戏,您可以看到这种情况:

> a = M.find(id)
> puts a.some_number
11
> a.some_number = 'pancakes'
 => "pancakes"
> puts a.some_number
0
> a.some_number = '$1,000'
 => "1,000"
> puts a.some_number
0
> a.some_number = '1000'
 => "1000"
> puts a.some_number
1000
因此,您的数据清理必须在数据进入模型实例之前进行,因为一旦AR获得该值,您的
'$1000'
将变为
0
,并且所有内容都将丢失。我将逻辑放在控制器中,控制器的工作是在外部世界和模型之间进行调解,数据格式化和损坏当然也算作调解。因此,您的控制器中可以有如下内容:

def some_controller
    fix_numbers_in(:profit)
    # assign from params as usual...
end

private

def fix_numbers_in(*which)
    which.select { |p| params.has_key?(p) }.each do |p|
        params[p] = params[p].gsub(/\D/, '') # Or whatever works for you
    end
end
在ActiveRecord用它肮脏的小手处理你的数据并把事情弄得一团糟之前,一切都会变得干净


您可以通过覆盖模型中的
profit=
方法来做类似的事情,但这实际上不是模型的工作。

它只是模仿作者的RegExp。尽量不吓唬他)谢谢@jdoe我已经使用了你的建议,它的工作方式就像我想要的一样。我猜
u.price
返回实例变量的值。这是你制造的陷阱!什么意思?attr_accessor定义了两个方法-getter和setter,price方法返回实例变量的值,对吗?)陷阱在哪里?)您的
用户
ActiveRecord::Base
无关。事件,则
@pofit
变量将与
利润
DB属性无关。从
ActiveRecord::Base
继承您的
User
版本后,您应该将
@profit=
替换为
self.profit=
。否则,您将屏蔽
price
属性。但我认为你们是对的,我应该举一个关于Rails的例子,谢谢你们的好建议)我知道我可以在controller中做到这一点,但我希望在保存到模型本身之前自动化这个过程,因为我从不同的地方调用它。有什么想法吗?顺便说一句,谢谢你提供的信息丰富的答案,以及在错误的地方使用to_的方法。
def some_controller
    fix_numbers_in(:profit)
    # assign from params as usual...
end

private

def fix_numbers_in(*which)
    which.select { |p| params.has_key?(p) }.each do |p|
        params[p] = params[p].gsub(/\D/, '') # Or whatever works for you
    end
end