Question

I'm using restful_authentication in my app. I'm creating a set of default users using a rake task, but every time I run the task an activation email is sent out because of the observer associated with my user model. I'm setting the activation fields when I create the users, so no activation is necessary.

Anyone know of an easy way to bypass observers while running a rake task so that no emails get sent out when I save the user?

Thanks.

Was it helpful?

Solution

You could add an accessor to your user model, something like "skip_activation" that wouldn't need to be saved, but would persist through the session, and then check the flag in the observer. Something like

class User
  attr_accessor :skip_activation
  #whatever
end

Then, in the observer:

def after_save(user)
  return if user.skip_activation
  #rest of stuff to send email
end

OTHER TIPS

Rails 3.1 finally comes with API for this: http://api.rubyonrails.org/v3.1.0/classes/ActiveModel/ObserverArray.html#method-i-disable

ORM.observers.disable :user_observer
  # => disables the UserObserver

User.observers.disable AuditTrail
  # => disables the AuditTrail observer for User notifications.
  #    Other models will still notify the AuditTrail observer.

ORM.observers.disable :observer_1, :observer_2
  # => disables Observer1 and Observer2 for all models.

ORM.observers.disable :all
  # => disables all observers for all models.

User.observers.disable :all do
  # all user observers are disabled for
  # just the duration of the block
end

Where ORM could for example be ActiveRecord::Base

As a flag for the observer I like to define a class accessor called "disabled" so it reads like this:

class ActivityObserver < ActiveRecord::Observer
  observe :user

  # used in tests to disable the observer on demand.
  cattr_accessor(:disabled)
end

I put it as a condition in the sensitive callbacks

def after_create(record)
       return if ActivityObserver.disabled
       # do_something
end

and I just turn the flag on when needed

ActivityObserver.disabled=true

Another one you can try (rails 3)

config.active_record.observers = :my_model_observer unless File.basename($0) == 'rake'

In generally, for these sorts of situations, you can:

  1. Set up a mock object to "absorb" the unwanted behavior
  2. Have an externally accessible flag / switch that the observers respect to inhibit the behavior
  3. Add logic to the observer to detect when the behavior is unneeded in general (e.g. what dbarker suggests)
  4. Have a global flag "testing", "debug", "startup" or whatever that changes low level behavior
  5. Introspect and remove the observers
  6. Add a method to your model that performs an alternative, unobserved version of the task (sharing implementation with the normal method as much as possible).

In this case, I'd say #3 is your best bet.

When running tests on an app I am working on, I use the following:

Model.delete_observers

Disabling observers for Rails 3 it's simple:

Rails.configuration.active_record.observers = []

You can take the method off the observer;

MessageObserver.send(:remove_method, :after_create)

Will stop the :after_create on MessageObserver by removing it.

I came here looking for the an answer to the same... none of the above seemed to do the trick (or involve adding migration-specific logic to my application code -- boo).

Here's what I came up with (a bit lame that it needs to go in each relevant migration, but...)

class ChangeSomething < ActiveRecord::Migration

  # redefine...
  class MessageObserver < ActiveRecord::Observer
    def after_create(observed) ; end
    def after_update(observed) ; end
  end

  def self.up
    # Message create/update stuff...
  end
end
User.skip_callback("create", :after, :send_confirmation_email)

....

User.set_callback("create", :after, :send_confirmation_email)

More on this:

Disabling Callbacks in Rails 3

There isn't a straightforward way to disable observers that I know of, but it sounds possible to add logic to your observer to not send an email when the activation code is set...

As others have hinted; I would wrap the unwanted logic in your Observer with a simple if statement.

def after_create
  send_email if RAILS_ENV == "production"
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top