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