In my application I have a user confirmation process. When a user signs up four things happen:
An account_status_id is set to 1 (unconfirmed)
The user is signed in (now current_user exists)
A new_account_confirmation_token is generated
A confirmation email is sent to the new user with a link that includes the new_account_confirmation_token
I initially tried to handle the confirmation link with this method. It finds the user without issue and the code flows through the update_attributes! method, however it wasn't updating the account_status. From what I can tell it is due to the fact that the current_user object exists, therefore the user Im trying to update is already "in memory". Is that correct?
def new_account_confirmation
#title = "Account Confirmation"
logger.info("User is not logged in")
#user = User.find_by_new_account_confirmation_token(params[:confirm_id])
if #user
#user.update_attributes!(:account_status_id => 2)
else
redirect_to root_path
end
end
My work around is as follows. The code below works but I'd like to know why the code above doesn't work. Why won't it update the account_status?
def new_account_confirmation
#title = "Account Confirmation"
if current_user
logger.info("User is logged in")
current_user.update_attributes!(:account_status_id => 2)
else
logger.info("User is not logged in")
#user = User.find_by_new_account_confirmation_token(params[:confirm_id])
if #user
#user.update_attributes!(:account_status_id => 2)
else
redirect_to root_path
end
end
end
Even if your user is "in memory" as you say, that's no reason for it not to update. I believe your update IS happening but you're just not seeing it because current_user is not in sync with #user.
I don't know how you're verifying that #user is not being updated but if update_attributes! is not throwing an error then it's being saved.
Related
I am using Devise for authentication. I want to have users the ability to change their passwords - so I have added this action to my controller:
def update_password
if current_user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
sign_in(current_user, bypass: true)
redirect_to settings_path, notice: "Your password has been updated!"
else
current_user.errors.each do |err|
puts "-> #{err.inspect}"
end
redirect_to settings_path, alert: "Problem: #{current_user.errors.inspect}"
end
end
If a user enters the right current password and the new password (plus its confirmation), then the password is changed - that's good.
However, when there's a problem, such as the new password + its confirmation is not matched, or if the entered current password is not correct, or if eg. the new password is not long enough - then it fails, that's good as well.
However, I'd want to display to users why the password has not been changed - how do I find out the reason for not changing the password? Where do I find the error messages?
Thank you in advance.
you will need to validate some of these on the controller level and manually like the confirmation of the new password and the old password with a simple if the did not match then redirect_back and flash and error (it would be nice also to have a small JS script to evaluate this instead of waiting for a request to come to the controller but also keep the validation in the controller)
and for the old password confirmation, you will need to use Devise::Encryptor.compare(klass, hashed_password, password) and also raise a error manually then go on to storing a new password and check if the record did save normally
def update_password
old_password = devise_parameter_sanitizer.require(:old_password)
new_password = devise_parameter_sanitizer.require(:new_password)
new_password_confirmation = devise_parameter_sanitizer.require(:new_password_confirmation)
if new_password != new_password_confirmation
redirect_to settings_path, alert: "NEW PASSWORD DO NOT MATCH"
end
if Devise::Encryptor.compare(User, current_user.encrypted_password, old_password)
redirect_to settings_path, alert: "SAME OLD PASSWORD ERROR!"
end
if current_user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
redirect_to settings_path, notice: "Your password has been updated!"
else
redirect_to settings_path, alert: person.errors.full_messages.to_sentences
end
end
Ive read plenty of questions asking this exact question, but havent gotten a great answer.
Right now a user goes to the site, and enters their email in. After they click submit I would like to clear their session/log them out so that they could enter in another email address, so it will save to the DB.
My hacky solution was to call the reset session in my user controller after a user was saved. This did not work.
I then proceeded to call the sign_out method provided via devise on user save, but that did not work.
Does anyone have any thoughts/solutions?
user_controller.rb
def create
#user = User.new(user_params)
#if #user.save
#reset_session
#sign_out :user
#flash: 'User was successfully created.'
#User.find(user_params).forget_me!
#else
#render action: 'new'
#end
end
I did this using the following code
reset_session
#current_user = nil
How do I Get the current user id in my controller using devise?
In my controller I have something like this:
def index
me = current_user
c = User.find(me)
#sheets = c.time_sheets
end
I am getting an error say that "Couldn't find User without an ID".
If If I put in a static number in the User.find() it works but of course that is not what I want. Any help would be greatly appreciated.
thanks!
Replace current index action as below
def index
if current_user
#sheets = current_user.time_sheets
else
redirect_to new_user_session_path, notice: 'You are not logged in.'
end
end
If user is not logged in, i.e., current_user=nil then user would be redirected to login page with a flash message.
I have been trying to solve the following problem for a couple of days. Forgive me if this is a common problem as I am new to rails and probably couldn't query the right question/keyword in stackoverflow or google.
I am building a system where a user will get an invite via email, click on a unique link, be taken to a page where he/she can accept or decline the invitation. I am getting stuck at the part where the user accepts or declines the invitation.
I've built it around two controllers: an invitations controller and a confirmations controller.The invitations controller creates a record containing a name, an email, and a uniquely generated token. The controller then emails a link with the token to the defined email. The link points to the confirmations controller and passes the unique token from the invitation. However, when clicking on the link and accepting the invitation, I get the following error:
NoMethodError in ConfirmationController#confirm
undefined method `update_attribute' for nil:NilClass
Here is some of the code for solving this issue:
Confirmation_controller.rb
class ConfirmationController < ApplicationController
def new
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
end
def confirm
if #confirmation.update_attribute(:accepted, true)
flash[:success] = "Invitation confirmed!"
redirect_to 'static_pages/home'
else
flash[:notice] = "Failed :("
redirect_to 'static_pages/home'
end
end
end
routes.rb
match '/confirmation/:invite_token', to: 'confirmation#new'
match '/confirmation/:invite_token/confirm', to: 'confirmation#confirm'
app/views/confirmation/new.html.erb
Click here to accept:
<%= link_to "Confirm", :controller => "confirmation", :action => "confirm" %>
You need to get your Invitation in the confirm method too.
If you want rails to raise an exception if no invitation was found
def confirm
#confirmation = Invitation.find_by_invite_token!(params[:invite_token])
#confirmation.update_...
end
No exception will be raise. You may want to check manually with a condition in the following case.
def confirm
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
if #confirmation
#confirmation.update_...
else
# do something
end
end
You should find confirmation record before calling update_attribute on it, like you did it in new action:
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
Or, to throw exception when the record is not found and to render 404 page to the user:
#ocnfirmation = Invitation.find_by_invite_token!(params[:invite_token])
The problem is that you never told the program what #confirmation is. What you should do is find it first then run the update. Note this is different from the different answers, just thought I would throw in some variety.
def confirm
# You're missing this line below. Basic search for the confirmation.
# Note too that you will have to pass in the parameter `invite_token` for it to work
# I'm also assuming invite_token is unique among each invitation
confirmation = Invitation.where(invite_token: params[:invite_token])
# Notice that I'm first checking to see if the confirmation record exists, then doing an update
if confirmation and confirmation.update_attribute(:accepted, true)
flash[:success] = "Invitation confirmed!"
redirect_to 'static_pages/home'
else
flash[:notice] = "Failed :("
redirect_to 'static_pages/home'
end
end
i already have the crm_member_list table and also can successfully login ,now i want to add a column to crm_member_list table called "failed_times" to record the failed times.when the failed_times more than 5 times.user account is locked.
i define a method called add_failed_times in the crm_member_list model.
def self.add_failed_times(mbr_id)
member = find_by_mbr_id(mbr_id)
failed_times = member.failed_times.to_i+1
end
in the session controller,
def create
member = CrmMemberList.authenticate(params[:session][:mbr_id],params[:session][:password])
if member.nil?
user= CrmMemberList.find_by_mbr_id(params[:session][:mbr_id])
if user.nil?
flash.now[:error] = "Invalid passport/password combination."
#title = "User nil"
render 'new'
else
times = CrmMemberList.add_failed_times(params[:session][:mbr_id])
if times.to_i=1
user.failed_times=times
user.save
flash.now[:error] = "Invalid passport/password combination."
#title = "Less than 6"
render 'new'
else
#title ="Locked"
render 'failed'
end
end
else
sign_in member
redirect_to member
end
end
How can i resolve this problem?
thanks
the save is false.
I'm guessing the save is false due to some validation error. Probably the password and password confirmation don't match. You can call
user.save(:validates => false)
which bypasses the validation.
If you're unsure what the error is, after you've called user.save, you can output
user.errors
To get the errors that are stopping your save.
What about using a gem to handle the whole authentication stuff (including account locking) automagically : https://github.com/binarylogic/authlogic ?