How can I avoid running ActiveRecord callbacks?

2019-01-02 22:11发布

I have some models that have after_save callbacks. Usually that's fine, but in some situations, like when creating development data, I want to save the models without having the callbacks run. Is there a simple way to do that? Something akin to...

Person#save( :run_callbacks => false )

or

Person#save_without_callbacks

I looked in the Rails docs and didn't find anything. However in my experience the Rails docs don't always tell the whole story.

UPDATE

I found a blog post that explains how you can remove callbacks from a model like this:

Foo.after_save.clear

I couldn't find where that method is documented but it seems to work.

25条回答
唯我独甜
2楼-- · 2019-01-02 22:21

For creating test data in Rails you use this hack:

record = Something.new(attrs)
ActiveRecord::Persistence.instance_method(:create_record).bind(record).call

https://coderwall.com/p/y3yp2q/edit

查看更多
聊天终结者
3楼-- · 2019-01-02 22:24

rails 3:

MyModel.send("_#{symbol}_callbacks") # list  
MyModel.reset_callbacks symbol # reset
查看更多
贼婆χ
4楼-- · 2019-01-02 22:24

Why would you want to be able to do this in development? Surely this will mean you are building your application with invalid data and as such it will behave strangely and not as you expect in production.

If you want to populate your dev db with data a better approach would be to build a rake task that used the faker gem to build valid data and import it into the db creating as many or few records as you desire, but if you are heel bent on it and have a good reason I guess that update_without_callbacks and create_without_callbacks will work fine, but when you are trying to bend rails to your will, ask yourself you have a good reason and if what you are doing is really a good idea.

查看更多
Emotional °昔
5楼-- · 2019-01-02 22:26

None of these points to without_callbacks plugin that just does what you need ...

class MyModel < ActiveRecord::Base
  before_save :do_something_before_save

  def after_save
    raise RuntimeError, "after_save called"
  end

  def do_something_before_save
    raise RuntimeError, "do_something_before_save called"
  end
end

o = MyModel.new
MyModel.without_callbacks(:before_save, :after_save) do
  o.save # no exceptions raised
end

http://github.com/cjbottaro/without_callbacks works with Rails 2.x

查看更多
beautiful°
6楼-- · 2019-01-02 22:29

Another way would be to use validation hooks instead of callbacks. For example:

class Person < ActiveRecord::Base
  validate_on_create :do_something
  def do_something
    "something clever goes here"
  end
end

That way you can get the do_something by default, but you can easily override it with:

@person = Person.new
@person.save(false)
查看更多
够拽才男人
7楼-- · 2019-01-02 22:31

The most up-voted answer might seem confusing in some cases.

You can use just a simple if check if you would like to skip a callback, like this:

after_save :set_title, if: -> { !new_record? && self.name_changed? }
查看更多
登录 后发表回答