Rails 4.使用before_validation回调时的奇怪行为

时间:2015-06-24 14:06:38

标签: ruby-on-rails ruby ruby-on-rails-4

假设数据库中有用户记录。我们决定在模型中添加验证。型号:

class User < ActiveRecord::Base
  validates_format_of :name, with: /\A[^\d]*\z/, allow_blank: true

  before_validation :delete_digits_from_name

  def delete_digits_from_name
    self.name = name.gsub!(/\d/, '')
  end
end

控制台中的场景1:

User.create(name: 'Username 15')
User.last
=> #<User id: 14154, name: "Username"

没关系。但是有旧记录(在添加验证之前创建)和..场景2:

user = User.first
=> #<User id: 1, name: "Username 15"
user.save
=> true
user
=> #<User id: 1, name: "Username"
user.reload
=> #<User id: 1, name: "Username 15"

但为什么?为什么改变没有保存?

1 个答案:

答案 0 :(得分:1)

gsub!中的delete_digits_from_name更改了名称,因此Rails认为name与从DB加载的内容相同。它是同一个对象,即使你已经改变了它的价值。 Rails执行此操作以在没有数据更改时优化远程数据库更新,并且就地编辑会使其混淆。

切换到self.name = self.name.gsub(/\d/, '')(没有!)会分配一个新的String,Rails会认为它是脏的,需要保存。

您还可以在name_will_change!之后添加gsub!告诉Rails属性需要保存。