Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Allow controller to pass params to reset password email #2207

Closed
wants to merge 4 commits into from

5 participants

Danial Pearce José Valim Vince Wadhwani Emile Victor Vasiliy Ermolovich
Danial Pearce

These changes allow the password controller to pass parameters to the reset password email via the optional mailer arguments added in devise 2.2.0.

Unfortunately this means you shouldn't really call send_reset_password_instructions on the class method, because that method already takes a hash of arguments used to find the resource. I could have used an optional mailer key in that hash, the same way rails allows for a html key in hash options for things like form_for etc, but I thought this was a better option. Happy to discuss any alternative ideas people might have.

Also, I only implemented controller parameters for the passwords controller, but the framework is there for confirmable and lockable as well. I just wasn't as familiar with those controllers as I don't use them, so I didn't fell 100% comfortable in changing them.

José Valim
Owner

Thanks for the PR. One small note:

Unfortunately this means you shouldn't really call send_reset_password_instructions on the class method, because that method already takes a hash of arguments used to find the resource.

It could simply accept a second argument with the delivery options. That would be my preferred approach.

Danial Pearce

Thanks Jose. I will do it that way and see how it looks. Generally people don't like methods that take 2 lots of hashes.

Danial Pearce

Branch has been updated @josevalim , thank you for your comments.

Vince Wadhwani

I currently have an open stackoverflow question on this exact issue. Is there a particular version of the gem that this feature is included in? It looks pretty straight forward but any documentation I can view or contribute?

José Valim
Owner

This feature has not been merged yet, so the best you can do is to depend on @tigris fork.

Vasiliy Ermolovich nashby closed this
Vasiliy Ermolovich nashby reopened this
Vince Wadhwani

Ok perfect. Thanks @tigris and @josevalim; I've done just that and it seems to be working as expected. Let me know if there's anything I can do to help this along.

José Valim
Owner

I merged this pull request locally and I tried adding similar feature to confirmable. However, since the confirmable is sending on creation, we can't pass the parameters to the mailer using the current structure. That said, I am dropping this approach for now because I couldn't find a way to make it work consistently across the request. Maybe the best option is to store the request information on a thread local variable.

José Valim josevalim closed this
José Valim
Owner

Regardless, thanks for the pull request @tigris !

Emile Victor

Hey @josevalim, is there any movement on this? I was considering making my own pull request with this feature until I saw this one. I think this would be a useful feature if we could somehow introduce it. In the meantime, I'm going to be doing a bit of a kludge in my own codebase to get it working.

Danial Pearce

FWIW, I implemented this on my project by storing the params in a thread local variable. Using the request_store gem I have a before_filter in my ApplicationController setting the appropriate variables, in then in UserMailer I can pull them out as needed.

The issue of course is if you ever want to call UserMailer methods manually from a console or cron or something, and rely on any params from request_store then you are going to need to account for that with some defaults, or allow them to be passed in.

I left my branch around cos I knew it worked and hoped devise would find a way to make it happen, but I needed upgraded features from newer devise so that is why I went with the solution above rather than my own branch.

Vince Wadhwani

@tigris We're using your branch at the moment but I cloned a copy just in case. Thanks for your work - I'm sad this didn't make it into master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
2  app/controllers/devise/passwords_controller.rb
View
@@ -10,7 +10,7 @@ def new
# POST /resource/password
def create
- self.resource = resource_class.send_reset_password_instructions(resource_params)
+ self.resource = resource_class.send_reset_password_instructions(resource_params, mailer_params)
if successfully_sent?(resource)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
9 app/controllers/devise_controller.rb
View
@@ -58,6 +58,15 @@ def _prefixes #:nodoc:
protected
+ # Allows controllers to pass params to mailers.
+ # This may seem odd, but `super` here is ApplicationController and we want the
+ # params from there to override our defaults here, but only if it exists.
+ def mailer_params
+ default = {}
+ default.merge!(super) if defined?(super)
+ default
+ end
+
# Checks whether it's a devise mapped resource or not.
def assert_is_devise_resource! #:nodoc:
unknown_action! <<-MESSAGE unless devise_mapping
6 lib/devise/models/authenticatable.rb
View
@@ -140,13 +140,13 @@ def devise_mailer
#
# protected
#
- # def send_devise_notification(notification)
- # pending_notifications << notification
+ # def send_devise_notification(notification, opts)
+ # pending_notifications << { type: notification, opts: opts }
# end
#
# def send_pending_notifications
# pending_notifications.each do |n|
- # devise_mailer.send(n, self).deliver
+ # devise_mailer.send(n[:type], self, n[:opts]).deliver
# end
# end
#
8 lib/devise/models/recoverable.rb
View
@@ -43,9 +43,9 @@ def reset_password!(new_password, new_password_confirmation)
end
# Resets reset password token and send reset password instructions by email
- def send_reset_password_instructions
+ def send_reset_password_instructions(opts = {})
generate_reset_password_token! if should_generate_reset_token?
- send_devise_notification(:reset_password_instructions)
+ send_devise_notification(:reset_password_instructions, opts)
end
# Checks if the reset password token sent is within the limit time.
@@ -105,9 +105,9 @@ module ClassMethods
# password instructions to it. If user is not found, returns a new user
# with an email not found error.
# Attributes must contain the user's email
- def send_reset_password_instructions(attributes={})
+ def send_reset_password_instructions(attributes={}, mailer_params={})
recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
- recoverable.send_reset_password_instructions if recoverable.persisted?
+ recoverable.send_reset_password_instructions(mailer_params) if recoverable.persisted?
recoverable
end
Something went wrong with that request. Please try again.