views:

3725

answers:

8

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.

+1  A: 

Not the cleanest way, but you could wrap the callback code in a condition that checks the Rails environment.

if Rails.env == 'production'
  ...
james
+3  A: 

You could try something like this in your Person model:

after_save :something_cool, :unless => skip_callbacks

def skip_callbacks
  ENV[RAILS_ENV] == 'development' # or something more complicated
end

EDIT: after_save is not a symbol, but that's at least the 1,000th time I've tried to make it one.

Sarah Mei
A: 

The only way to prevent all after_save callbacks is to have the first one return false.

Perhaps you could try something like (untested):

class MyModel < ActiveRecord::Base
  attr_accessor :skip_after_save

  def after_save
    return false if @skip_after_save
    ... blah blah ...
  end
end

...

m = MyModel.new # ... etc etc
m.skip_after_save = true
m.save
thenduks
+19  A: 

I just investigated this and I think I have a solution. There are two ActiveRecord private methods that you can use:

update_without_callbacks
create_without_callbacks

You're going to have to use send to call these methods. examples:

p = Person.new(:name => 'foo')
p.send(:create_without_callbacks)

p = Person.find(1)
p.send(:update_without_callbacks)

This is definitely something that you'll only really want to use in the console or while doing some random tests. Hope this helps!

efalcao
its not working for me. I am using rails 3. i am getting an error like this:--undefined method `update_without_callbacks' for #<User:0x10ae9b848>
piemesons
Your suggestion is not working but the blog post mentioned in the update part is working..
piemesons
A: 

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.

railsninja
I'm not trying to save without validations, just without callbacks. My app is using callbacks to write some static HTML to the filesystem (sort of like a CMS). I don't want to do that while loading dev data.
Ethan
Was just a thought, I guess whenever in the past I've seen this kind of question it's trying to get around stuff for bad reasons.
railsninja
+2  A: 

Perhaps a better 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)
Ryan Heneise
+1  A: 

Looks like one way to handle this in Rails 2.3 (since update_without_callbacks is gone, etc.), would be to use update_all, which is one of the methods that skips callbacks as per section 12 of the Rails Guide to validations and callbacks.

Also, note that if you are doing something in your after_ callback, that does a calculation based on many association (i.e. a has_many assoc, where you also do accepts_nested_attributes_for), you will need to reload the association, in case as part of the save, one of its members was deleted.

chrisrbailey
A: 

none of these points to without_callbacks plugin that just does what U 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

kares