I am using Devise for authentication in my Rails app. The password management including reset password mailers, etc. is handled via a controller that derives from Devise::PasswordsController. Something like:
class Users::PasswordsController < Devise::PasswordsController
def new
if not set_actionmailer_settings
error = I18n.t('invalid_paswd_config')
redirect_to new_user_session_path,
:flash => { :error => error } and return
end
super
end
end
I have now moved to a new UI that does not use Rails UI. Instead it calls into the Rails APIs. In the email that is sent to the user for resetting password, if I want to use a use a custom password reset URL, how do I do it?
try this in your routes.rb
map.devise_for :users, controllers: {passwords: "users/passwords"}, path_names: {
new: :new
}
Related
I have been following Ryan Boland's Rails multitenancy tutorial, but have run into a snag with devise_invitable.
I create a new account and user/account owner on a chosen subdomain (mysubdomain.lvh.me:3000), from which I can send a user invitation just fine. I open the invitation link in an incognito Chrome session to ensure I am not logged in or have any current session. Upon clicking on the invitation link, I am redirected to the sign in page (mysubdomain.lvh.me:3000/users/sign_in) and see a flash notice: "The invitation token provided is not valid!"
Related to this one:
Rails 4 devise_invitable invitation token invalid
[SOLVED]
In case anyone has the same issue, override the invitations controller and change the Tenant with Apartment:
# app/controllers/users/invitations_controller.rb
class Users::InvitationsController < Devise::InvitationsController
private
def resource_from_invitation_token
Apartment::Tenant.switch!(request.subdomain) //ADD THIS BABY!
unless params[:invitation_token] &&
self.resource = resource_class.find_by_invitation_token(params[:invitation_token], true)
set_flash_message(:alert, :invitation_token_invalid)
redirect_to after_sign_out_path_for(resource_name)
end
end
end
Remember to update your routes also, like this:
# config/routes.rb
devise_for :users, :controllers => { :invitations => 'users/invitations' }
I have a custom mailer (UserMailer.rb) and a few methods to override the default Devise methods for the welcome email and forgot password emails. The mailer uses a custom template to style the emails--and it works great.
In config/initializers, I have a file with
module Devise::Models::Confirmable
# Override Devise's own method. This one is called only on user creation, not on subsequent address modifications.
def send_on_create_confirmation_instructions
UserMailer.welcome_email(self).deliver
end
...
end
(Again, UserMailer is setup and works great for the welcome email and reset password email.)
But what's not working is the option to "Resend confirmation instructions." It sends with the default Devise styling and I want it to use the styling of my mailer layout. I know I can manually add the layout to the default Devise layout, but I'd like to keep DRY in effect and not have to do that.
I've tried overriding the send_confirmation_instructions method found here, but I'm getting a wrong number of arguments (1 for 0) error in create(gem) devise-2.2.3/app/controllers/devise/confirmations_controller.rb at
7 # POST /resource/confirmation
8 def create
9 self.resource = resource_class.send_confirmation_instructions(resource_params)
In my initializer file, I'm able to get to this error by adding a new override for Devise, but I'm probably not doing this correctly:
module Devise::Models::Confirmable::ClassMethods
def send_confirmation_instructions
UserMailer.send_confirmation_instructions(self).deliver
end
end
Any ideas?
You don't have to go through that initializer to do that. I've done this by overriding the confirmations controller. My routes for devise look like:
devise_for :user, :path => '', :path_names => { :sign_in => 'login', :sign_out => 'logout', :sign_up => 'signup'},
:controllers => {
:sessions => "sessions",
:registrations => "registrations",
:confirmations => "confirmations"
}
Then, create the confirmations_controller and extend the Devise::ConfirmationsController to override:
class ConfirmationsController < Devise::ConfirmationsController
In that controller, I have a create method to override the default:
def create
#user = User.where(:email => params[:user][:email]).first
if #user && #user.confirmed_at.nil?
UserMailer.confirmation_instructions(#user).deliver
flash[:notice] = "Set a notice if you want"
redirect_to root_url
else
# ... error messaging or actions here
end
end
Obviously, in UserMailer you can specify the html/text templates that will be used to display the confirmation message. confirmation_token should be a part of the #user model, you can use that to create the URL with the correct token:
<%= link_to 'Confirm your account', confirmation_url(#user, :confirmation_token => #user.confirmation_token) %>
I am looking for a customization in devise where if we click on forgot password it should send the mail to any e-mail id . Something like it happens in Gmail, irrespective of the email id exists or not.
Screen 1
Screen 2
Currently what i have is this in which it tries to validate with the valid users in the system.
The Devise, recoverable module takes care of this
def send_reset_password_instructions(attributes={})
recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
recoverable.send_reset_password_instructions if recoverable.persisted?
recoverable
end
How can i remove this validation and have email sent to any Email id?
There is a Devise configuration called paranoid that, when set to true, would change the message in a way to avoid e-mail enumeration. Just set config.paranoid = true in your Devise configuration.
My solution would be to extend/override Devise's passwords controller. To do this, create a controller (let's call it passwords) that inherits from Devise's passwords controller, like this:
class PasswordsController < Devise::PasswordsController
Then edit your routes file so this change takes effect:
devise_for :users, :controllers => { :passwords => 'passwords' }
Now, you'll want to override the create action. There are several ways you could do this but since I'm not sure of what you want to do, I'll show you 2 things you could do:
You only want to prevent the "Email not found" error so that people can't find which emails exist or not in your database:
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
end
You really want to send emails to any entered email:
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
unless successfully_sent?(resource)
Devise::Mailer.reset_password_instructions(resource).deliver
end
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
end
Now, the problem with this last solution is that you are sending an email to a user that doesn't exist... And so when the user comes back, he won't be able to enter his new password since his user account can't be found. But if you really want to do this, hopefully I set you on the right track.
When using recaptcha for Devise I have to make a new custom registrations controller and my issue is I get a missing template error when their is an error for the email, password or password confirmation because its hitting a route that doesn't even exist.
Template is missing
Missing template registrations/new
The recaptcha works on its own error and renders back to the same page but not for the others.
class RegistrationsController < Devise::RegistrationsController
def create
if verify_recaptcha
super
else
flash.delete :recaptcha_error
build_resource
clean_up_passwords(resource)
flash[:alert] = "There was an error with the recaptcha code below."
render :template => '/devise/registrations/new'
end
end
end
devise_for :users, :controllers => { :registrations => "registrations" }
It should be hitting the same page the recaptcha does on errors ('/devise/registrations/new')How do I correct this issue?
Thanks.
Try moving the templates from /views/devise/registrations to just /views/registrations. (And changing the reference in your code from /devise/registrations/new to just /registrations/new.)
Add following line to your config/application.rb file
config.paths['app/views'] << 'app/views/devise'
As the name says, I am using devise for user auth in a rails 3 app
Upon user log out, there is a flash notice, "User Successfully signed out" that I don't want to appear. However, I can't figure out how to remove the notice.
Is there a way to get around just making it blank? I would like to completely remove the notice so that, ideally, there's not even an html div for notice
If you explicitly put in a blank string for this in your locale file, then Devise "won't bother" to render the message at all (e.g. there won't even be an empty HTML div).
#en.yml
devise:
sessions:
signed_in: 'Signed in successfully.'
signed_out: ''
My routes.rb
devise_for :users, :controllers => {
sessions: 'user/sessions'
}
My controller "account/sessions_controller.rb"
class User::SessionsController < Devise::SessionsController
def destroy
super
flash.delete(:notice)
end
end