Reputation: 2360
I'm trying to override a Devise controller to have some minor changes, for example adding a flash message when requesting a confirmation email for an unregistered email address.
I tried to override Devise::ConfirmationsController
1 this way:
# app/controllers/confirmations_controller.rb
class ConfirmationsController < Devise::ConfirmationsController
include Devise::Controllers::InternalHelpers # tried to add this, no success
def create
self.resource = resource_class.send_confirmation_instructions(params[resource_name])
if successfully_sent?(resource)
respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
else
respond_with(resource)
end
end
end
I think I added the route correctly:
devise_for :users, :controllers => { :confirmations => "confirmations" }
My controller method gets called, however it raises this exception:
NoMethodError in ConfirmationsController#create
undefined method `successfully_sent?' for #<ConfirmationsController:0x007fa49e229030>
In my overridden controller, I just copied the code of Devise:: ConfirmationsController#create
, which itself calls successfully_sent?(resource)
The successfully_sent?
method is defined in InternalHelpers
2, this is why I tried to add include Devise::Controllers::InternalHelpers
This is not the first time I try to override a Devise controller, and this is not the first time I fail. I always managed to get a workaround, but I'd like to understand what I'm missing... Thanks in advance for your help!
[EDIT] Devise is in version 1.4.9 Rails is 3.0.10
Upvotes: 1
Views: 3053
Reputation: 2360
Well, thanks to the help of Kyle in my question's comments, I will write the correct answer to this beginner's mistake.
Instead of looking at my own version of Devise to override the controller, I was simply looking at Devise's Github repository. Since the controller I was trying to override had changes between my version and the last committed one, the helper method I was trying to use was simply not defined in my version...
As indicated by Kyle, you can use bundle open devise
to look at the code of the gem you're actually using, or you can look at its version number with gem list devise
and find the code for this release on Github (for Devise they set the tags for each release so that you can browse the code for release 1.4.9 by selecting the corresponding tag).
Doing this, I would have overrode my controller's create
method with the following code instead:
def create
self.resource = resource_class.send_confirmation_instructions(params[resource_name])
if successful_and_sane?(resource)
set_flash_message(:notice, :send_instructions) if is_navigational_format?
respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
else
respond_with_navigational(resource){ render_with_scope :new }
end
end
which uses successful_and_sane?
and not successfully_sent?
...
To conclude this answer, there may be a better way of adding a flash message to this method than overriding it. jarrad is advising to use around_filter
, but I can't get it to work yet and I'm unsure I can still change the rendered view after I yielded it from the filter method... Comments welcomed!
Upvotes: 2
Reputation: 3292
This may not help you understand why overriding the Devise controller is failing, but it will keep your code DRY in that you do not need to copy the code from Devise::ConfirmationsController#crete
So, if you just want to set a flash message, look at Filters for ActionControllers
Specifically, look at the Around Filter:
class ConfirmationsController < Devise::ConfirmationsController
around_filter :my_custom_stuff, :only => :create
private
def my_custom_stuff
# do your thing here...
end
end
Upvotes: 1