Rails / ActiveRecord:字段规范化

问题描述 投票:0回答:6

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

我试过:

before_validation :normalize

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

没有工作。

ruby-on-rails activerecord model
6个回答
8
投票

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

5
投票

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

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

如果您想将其作为整数存储在数据库中,那么您肯定需要覆盖设置器:

 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 :)

祝你好运!


1
投票

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

你可以定义一个setter:

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

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

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


0
投票

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

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

0
投票

您应该从 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

0
投票

Rails 7.1 介绍

ActiveRecord::Base::normalizes

class User < ApplicationRecord
  normalizes :email, with: ->(email) { email.strip.downcase }
end

它在验证之前调用

这是安全的,因为没有(但可以选择)适用于

nil

它适用于持久性和查找器方法

User.create(email: " [email protected] \n")
# => #<User email: "[email protected]">

User.find_by(email: "\[email protected] \t")
# => #<User email: "[email protected]">

如果您也需要对

nil
值应用归一化,请使用
apply_to_nil: true
选项

class User < ApplicationRecord
  normalizes :email, with: ->(email) { email&.strip&.downcase || "[email protected]" }, 
end

"[email protected]"
电子邮件将在
nil
情况下分配)

如果您有遗留的非规范化记录,您可以使用

ActiveRecord::Base#normalize_attribute

对其进行规范化
user.email # => "[email protected]  "
user.normalize_attribute(:email)
user.email # => "[email protected]"
user.save
© www.soinside.com 2019 - 2024. All rights reserved.