ruby-on-rails Rails / ActiveRecord:字段归一化

3j86kqsm  于 2023-05-19  发布在  Ruby
关注(0)|答案(6)|浏览(144)

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

before_validation :normalize

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

没有工作。

omqzjyyz

omqzjyyz1#

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
falq053o

falq053o2#

我觉得你做得很对。本测试通过:

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

如果你想把它作为一个整数存储在数据库中,那么你肯定需要覆盖setter:

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:)
祝你好运!

plicqrtu

plicqrtu3#

这样做的问题是,在一段时间内,非规范化的东西将存在于对象中;如果你的代码在规范化之前就能处理属性,那么这将是一个问题。
你可以定义一个setter:

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

不幸的是,我认为很多Rails表单都是直接写属性的,这也是我不倾向于使用它的原因之一。
或者你可以在传递控制器之前规范化参数。

zkure5ic

zkure5ic4#

ruby让你在a .我不知道,我以后再试试,但我想你应该用。

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

ql3eal8s5#

你应该从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
j2cgzkjk

j2cgzkjk6#

Rails 7.1引入了ActiveRecord::Base::normalizes

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

它在验证之前调用
它是安全的,因为它不适用于nil(但可以选择)
它同时适用于持久性和查找器方法

User.create(email: " ASDF@ExAmPLE.com \n")
# => #<User email: "asdf@example.com">

User.find_by(email: "\nasdf@examplE.CoM \t")
# => #<User email: "asdf@example.com">

如果您也需要对nil值应用标准化,请使用apply_to_nil: true选项

class User < ApplicationRecord
  normalizes :email, with: ->(email) { email&.strip&.downcase || "default@email.com" }, 
end

"default@email.com"电子邮件将在nil情况下分配)
如果有遗留的非规范化记录,可以使用ActiveRecord::Base#normalize_attribute规范化它

user.email # => "legacy@EMAIL.com  "
user.normalize_attribute(:email)
user.email # => "legacy@email.com"
user.save

相关问题