回调更改的ActiveRecord属性?

Mar*_*rio 17 events activerecord attributes ruby-on-rails

我知道ActiveRecord :: Dirty和相关的方法,但我没有看到我可以订阅属性更改事件的方法.就像是:

class Person < ActiveRecord::Base
  def attribute_changed(attribute_name, old_value, new_value)
  end

  #or

  attribute_changed do |attribute_name, old_value, new_value|
  end
end
Run Code Online (Sandbox Code Playgroud)

是否有Rails标准或插件?我觉得它必定存在于某个地方,我只是想念它.

Pet*_*net 18

cwninja的答案应该可以解决问题,但还有一点.

首先,使用write_attribute方法完成基本属性处理,因此您应该使用它.

Rails也有一个内置的回调结构,尽管它不允许传递有点烦人的参数,但它可能很好用.

使用自定义回调你可以这样做:

class Person < ActiveRecord::Base

  def write_attribute(attr_name, value)
    attribute_changed(attr_name, read_attribute(attr_name), value)
    super
  end

  private

    def attribute_changed(attr, old_val, new_val)
      logger.info "Attribute Changed: #{attr} from #{old_val} to #{new_val}"
    end

 end
Run Code Online (Sandbox Code Playgroud)

如果你想尝试使用Rails回调(如果你可能有多个回调和/或子类,则特别有用),你可以这样做:

class Person < ActiveRecord::Base
  define_callbacks :attribute_changed

  attribute_changed :notify_of_attribute_change

  def write_attribute(attr_name, value)
    returning(super) do
      @last_changed_attr = attr_name
      run_callbacks(:attribute_changed)
    end
  end

  private

    def notify_of_attribute_change
      attr = @last_changed_attr
      old_val, new_val = send("#{attr}_change")
      logger.info "Attribute Changed: #{attr} from #{old_val} to #{new_val}"
    end

end
Run Code Online (Sandbox Code Playgroud)


fgu*_*len 14

对于Rails 3:

class MyModel < ActiveRecord::Base
  after_update :my_listener, :if => :my_attribute_changed?

  def my_listener
    puts "Attribute 'my_attribute' has changed"
  end
end
Run Code Online (Sandbox Code Playgroud)

评论:https://stackoverflow.com/a/1709956/316700

我没有找到关于此的官方文档.

  • 我相信他想要在调用save之前在内存中更改属性时调用方法,即`my_object.some_attr ="foo"`会生成回调. (2认同)

pmo*_*sio 8

对于Rails 4

def attribute=(value)
  super(value)
  your_callback(self.attribute)
end
Run Code Online (Sandbox Code Playgroud)

如果要覆盖的属性值,你应该使用write_attribute(:attribute, your_callback(self.attribute)),而不是attribute=否则你会在它循环,直到你得到一个堆栈太深例外.


cwn*_*nja 5

尝试:

def attribute_changed(attribute_name, old_value, new_value)
end

def attribute=(attribute_name, value)
  returning(super) do
    attribute_changed(attribute_name, attribute_was(attribute_name), attribute(attribute_name))
  end
end
Run Code Online (Sandbox Code Playgroud)

刚刚发明了这个,但它应该工作.