可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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
回答2:
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
回答3:
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
回答4:
Another one you can try (rails 3)
config.active_record.observers = :my_model_observer unless File.basename($0) == 'rake'
回答5:
In generally, for these sorts of situations, you can:
- Set up a mock object to "absorb" the unwanted behavior
- Have an externally accessible flag / switch that the observers respect to inhibit the behavior
- Add logic to the observer to detect when the behavior is unneeded in general (e.g. what dbarker suggests)
- Have a global flag "testing", "debug", "startup" or whatever that changes low level behavior
- Introspect and remove the observers
- 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.
回答6:
When running tests on an app I am working on, I use the following:
Model.delete_observers
回答7:
Disabling observers for Rails 3 it's simple:
Rails.configuration.active_record.observers = []
回答8:
You can take the method off the observer;
MessageObserver.send(:remove_method, :after_create)
Will stop the :after_create on MessageObserver by removing it.
回答9:
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
回答10:
User.skip_callback("create", :after, :send_confirmation_email)
....
User.set_callback("create", :after, :send_confirmation_email)
More on this:
Disabling Callbacks in Rails 3
回答11:
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...
回答12:
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