i am using the devise for my User account where i will get all the confirmation, user password instructions etc;
But i am having a condition where if user account is locked (where status is false in my scenario), he has to get a reset password link through email. This locking process is coded in other controller so we cannot use devise helpers.
my controller code:
def send_instruction
a=[]
if #answer1
a << '1'
end
if #answer2
a << '2'
end
if #answer3
a << '3'
end
if a.size <= 1
SiteMailer.unlock_user(current_user).deliver
current_user.update_attribute(:status,false)
destroy_user_session_path(current_user)
flash[:error]= "Your account is locked"
redirect_to new_user_session_path
else
redirect_to user_dashboard_path
end
mailers/site_mailer.rb:
class SiteMailer < ActionMailer::Base
include Devise::Mailers::Helpers
default from: "support#example.com"
def unlock_user(user)
#user = user
#url = "pwd_edit"
mail(to: #user.email, subject: 'Your account has been locked')
end
end
in mailer view:
Hi,
Your account with has been locked. Edit Profile:
"My link (edit_user_password_url(current_user)".
When i am going through this process, I am getting "No routes found" error. And my routes are correct. Please help me out.
That's because no current_user is present at that time. You should try this instead
edit_user_password_url(#user)
Related
working on a Passwords_Controller that allows the password to be changed, also validates if the user is using same password, or if they are trying to use different password, and another password to confirm. I have it set to "redirect_to" to my dashboard controller that lands them back to be the page to enter the password again before user is updated with new password.
currently I am getting a DoubleRenderError. I have some "puts" with extrapolation see if the logic is passing through the controller and rendering I'm new to rails, so i'm not exactly sure if its my redirect statements that are stopping the validation of old pw, new password - confirm password logic in my controller, or I have too many if statements that is forcing the controller to do double render.
(output of on the terminal with statements for error)
Redirected to http://127.0.0.1:3000/dashboard
true
is this working asdf <~~ test username
is this also working $2a$12$d5WadQunMyww2r4lnmqgveoXaq6WO6hNXvsG/h3RxqUxGFCp6tnWm
Redirected to
Completed 500 Internal Server Error in 738ms (ActiveRecord: 9.1ms | Allocations: 6474)
AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".):
this is my password controller
require 'bcrypt'
class PasswordsController < ApplicationController
include BCrypt
def passwordchanged
end
def update
user = current_user;
#user entered correct password
if user.authenticate(params[:password])
helpers.flash_message :danger, "current password doesnt match"
redirect_to '/dashboard'
end
puts "#{user.authenticate(params[:password])}"
puts "is this working #{params[:new_password]}"
puts "is this also working #{Password.new(user.password)}"
#if new password is the same as new password, doesnt not save
if Password.new(user.password) == params[:new_password]
helpers.flash_message :danger, "new password can't match current password, please try again"
redirect_to '/login'
end
puts "#{redirect_to '/login'}"
#if new password doesnt match confirm password
if params[:new_password] != params[:new_password_confirm]
helpers.flash_message :danger, "password, password confirm needs to match"
redirect_to '/dashboard'
end
puts "#{params[:new_password] != params[:new_password_confirm]}"
#create a new password and save the user ID
user.password = params[:new_password]
user.save
helpers.flash_message :success, "change successful, logout for new session"
redirect_to '/passwordchangesuccess'
end
end
this is my Application Controller
class ApplicationController < ActionController::Base
helper_method :current_user
def current_user
User.find_by(id: session[:user_id])
end
def authenticate_user!
redirect_to '/login' unless current_user
end
end
Within my application a User is created after a successful transaction
def create_real_user
return unless current_or_guest_user.is_guest?
generated_password = Devise.friendly_token.first(8)
#user = User.new(
is_guest: false,
first_name: params[:first_name],
last_name: params[:last_name],
email: params[:email],
password: generated_password,
password_confirmation: generated_password,
braintree_id: #result.transaction.customer_details.id
)
#user.save(validate: false)
RegistrationMailer.welcome(#user, generated_password).deliver_now
end
And as you can see an email is sent out and it advises that a password has been set for them but if they wish to change it then visit a link
Your current password is <%= #password %> but if you would like to change it then please visit <%= link_to 'Change my password', edit_user_registration_path(#user.id) %>
So when clicking this i get to the login screen but i would like to have the user automatically signed in and taken straight to the page where they can edit their password.
How would i go about this?
Thanks
There isn't a quick fix for this but it's possible.
Include a route for this special login case...
resources :users do
member do
get 'token_link'
end
end
This gives you a new helper method `token_link_user_path
You would need to create a token field in your User table when you create the record, and set it to some random value via a before_create
class User
before_create :generate_token
def generate_token
user.token = SecureRandom.urlsafe_base64(nil, false)
end
...
end
In your email include the link...
link_to 'access your account', token_link_user_path(#user.token)
In your User controller...
def token_link
#user = User.find_by(token: params[:id])
#user = nil if #user && #user.created_at < Time.now - 1.day
unless #user
flash[:error] = 'Invalid log in'
redirect_to root_path
end
#user.update_attribute(:token, nil)
... do here any processing, renders, or redirects you'd like
end
Note how we wipe out the token_link after it's been used, to prevent it from beign used twice. Along the same lines, we check that it's not older than a day since the record's been created.
I decided to customize(override) Devise's session controller to implement my own sign in logic. I've left the sessions#new controller alone and simply call super in it.
def new
super
end
However, I have removed the call to super in my custom sessions#create method so that I can send an HTTP request to a server for authentication. Subsequently, I either sign in the user or return the user to the sessions#new path to try their login again.
def create
#member = Member.find_by_username(params[:username])
response = authenticate_with_api
if response[:authenticated]
if #member
#member.update(response.[:member])
sign_in #member
else
#member.create(response.[:member])
sign_in #member
end
else
flash[:alert] = "Incorrect username or password"
flash[:error] = "Incorrect username or password"
flash[:notice] = "Incorrect username or password" #setting all the messages out of frustration!
redirect_to new_member_session_path
end
The logic flow is working correctly, however the flash messages are not displaying. I have set a flash message just before calling super in the new method to ensure that the view was setup properly:
def new
flash[:notice] = "Test flash message"
super
end
This works. I can see the flash message appear in the template. The only explanation I can come up with is that somehow, there are multiple redirects occurring. However, when I look in the logs, I can only see the redirect I specified. I have also tried using keep to persist the flash message through multiple requests, but even that does not work:
flash.keep[:notice] = "Test flash message"
redirect_to new_member_session_path #does not work
I also tried using now as a last ditch effort:
flash.now[:notice] = "Test flash message"
No dice. Lastly, I have tried placing the flash message inline with the redirect:
redirect_to new_member_session_path, flash: { :notice => "Test flash message" } #also does not work
I am at a loss. Not sure why the flash messages are being lost. I am running Rails 4.1.2 and Devise 3.2.4
EDIT:
I have decided this is not the best way to customize authentication. Instead, I've created a custom Warden strategy and told devise about it:
#config/initializers/devise.rb
config.warden do |manager|
manager.intercept_401 = false
manager.default_strategies(:scope => :member).unshift :member_login
end
I put all my logic in that file:
Warden::Strategies.add(:member_login) do
def member_params
ActionController::Parameters.new(#response).permit(:first_name, :last_name, :role, :username, :parkplace_user_id)
end
def valid?
params[:member] && ( params[:member][:username] || params[:member][:password] )
end
def authenticate!
member = Member.find_by_username(params[:member][:username])
if authenticate_with_ppd_api
if member
member.update(member_params)
success!(member)
else
member = Member.create(member_params)
success!(member)
end
else
fail!("Incorrect username or password")
end
end
def authenticate_with_api
#response = HTTParty.post('https://path.to.server/admin/login', body: { username: params[:member][:username], password: params[:member][:password] } )
#response = JSON.parse(#response.body).first
#response["authenticated"]
end
end
Flash messages are appearing now, but I have other problems with sign in. I created a new question for that. Thanks!
I'm setting up Devise such that users can log in and use the site without having confirmed their email address, similar to this question. But there are a couple of features on the site that users can't use unless they've confirmed.
OK, that's fine. I can check for current_user.confirmed?. If they're not confirmed, I can put a button on the page to have them request the confirmation be sent again.
The issue I'm having is that when they do this while logged in, the flash message they see on the result page is "You are already signed in." Which isn't ideal - I just want to put up the message that the confirmation was sent.
I'm starting down the path of trying to figure out which method of the Devise::ConfirmationController to override, and to what, but I'm hoping someone has done this already.
The reason the flash says "You are already signed in" is because the user is being redirected to new_session_path from the after_resending_confirmation_instructions_path_for method. I would override this method to check if they are logged in. If they are, then don't redirect to new_session_path, set your flash message and redirect to another page.
Override the confirmations controller by putting it in controllers/users/confirmations_controller.rb
class Users::ConfirmationsController < Devise::ConfirmationsController
protected
def after_resending_confirmation_instructions_path_for(resource_name)
if signed_in?
flash[:notice] = "New message here" #this is optional since devise already sets the flash message
root_path
else
new_session_path(resource_name)
end
end
end
Add your confirmationsController to routes->
devise_for :users, :controllers => {:confirmations => 'users/confirmations' }
I think it should look something like this:
module Devise
module ConfirmationsController
extend ActiveSupport::Concern
included do
alias_method_chain :show, :new_flash
end
def show_with_new_flash
# do some stuff
flash[:notice] = "New message goes here"
end
end
end
Could edit
config/locales/devise.en.yml to be more relavent at line:
failure:
already_authenticated: 'You are already signed in.'
or you could do this in your view where flash message has been added
<%=content_tag :div, msg, id: "flash_#{name}" unless msg.blank? or msg == "You are already signed in."%>
I'm using Devise 3.1.0, there's a different method for this scenario instead of after_resending_confirmation_instructions_path_for described in the top voted answer. I modified mine like so:
class Users::ConfirmationsController < Devise::ConfirmationsController
protected
def after_confirmation_path_for(resource_name, resource)
if signed_in?
set_flash_message(:notice, :confirmed)
root_path
elsif Devise.allow_insecure_sign_in_after_confirmation
after_sign_in_path_for(resource)
else
new_session_path(resource_name)
end
end
end
Update: this question has been answered (see below). I'll leave it up in case anyone can benefit in the future.
I am trying to get e-mail confirmations working on Authlogic using Rails 3. http://github.com/matthooks/authlogic-activation-tutorial
Authentication is working and the activation e-mails are being generated and sent, each containing a perishable token, but the perishable tokens are incorrect, in that they do not match the one saved in the user's record.
Upon following the token in the e-mail, I get: Exception in ActivationsController#create
Note: When I manually enter the correct token from the table into the URL, it validates and redirects as it is supposed to. Therefore, the only issue is that the perishable token being generated is not the same as the one being saved.
# UserMailer
class UserMailer < ActionMailer::Base
default :from => "notifications#myapp.com"
def registration_confirmation(user)
#user = user
mail(:to => "#{user.login} <#{user.email}>", :subject => "Registered")
end
def activation_instructions(user)
subject "Activate Your Account"
from "noreply#myapp.com"
recipients user.email
sent_on Time.now
body :account_activation_url => activate_url(user.perishable_token)
end
def welcome(user)
subject "Welcome to the site!"
from "noreply#myapp.com"
recipients user.email
sent_on Time.now
body :root_url => root_url
end
end
# E-mail itself:
To activate, click here: <%= #account_activation_url %>
The error is occurring on line 5 where the system tries and fails to find User by token:
class ActivationsController < ApplicationController
before_filter :require_no_user
def create
#user = User.find_by_perishable_token(params[:activation_code], 1.week) || (raise Exception)
raise Exception if #user.active?
if #user.activate!
flash[:notice] = "Your account has been activated!"
UserSession.create(#user, false) # Log user in manually
#user.deliver_welcome!
redirect_to home_url
else
render :controller => "welcome", :action => "linklogin"
end
end
end
It's funny - sometimes the process of asking the question itself reveals the answer.
In my users#create, there are different user types, and the action sets a couple of values after the initial validated save and saves the simple changes again without validation.
My e-mail was being sent in between the first and second saves, so of course by the time the user clicks on the activation e-mail, the perishable_token has already been reset.
I moved the mailing down to after the second save, and now the activation e-mail works perfectly.
Thank you very much for any time you've spent considering this problem. :)
Cirrus