Search code examples
ruby-on-railsrubyruby-on-rails-3validationforgot-password

Validations conflicts in Rails


I am working on a project and I am facing a problem which I tried to solve but no progress.

All these happened when I started to implement Forgot Password functionality for resetting password. I have a User Model which has validations for password and password_confirmation. I used these for registration and are working fine.

But for this functionality I am using a new controller called PasswordResets. I am generating a string called password_reset_token for my users table. And there is password_reset_sent_at which records the time a user asks for a reset. The process goes like this;

1) The User clicks Forgot Password?

2) He is redirected to a page where he is asked to enter his email.

3) Controller checks if the email is present in database, if yes then ;
3.1) I generate a random password_token by using SecureRandom and also time when he started the request.
3.2) Now the save happens here for sending the mail to user. Here the problem occurs. The password_reset_token is not getting saved into table.

The reason behind that is I am using validations for password and password _confirmation in User.rb. Here the action taking place is :update, so on update the record is asking for password and password_confirmation to be sent along with password_reset_token and the time.

But I tried solving by keeping validations as :on => :create, now it is working well but when I use the link for resetting my validations will not work for password and password_confirmation. This is like a deadlock for me. I know this is bit confusing, I am pasting some code to understand the problem.

My PasswordResets Controller create action:

  def create
    user= User.find_by_email(params[:email])
    if user
      user.send_password_reset
      UserMailer.password_reset(self).deliver
      flash[:success] = "Email sent with password reset instructions."
      redirect_to root_url
    else
      flash[:error] = "Email doesn't exit."
      render 'password_resets/new'
    end
  end

My User Model (user.rb)

class User < ActiveRecord::Base

  has_secure_password

  EMAIL_REGEX = /\A[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}\Z/i


  validates_confirmation_of :password_confirmation

  validates :username, :presence => true,
                       :uniqueness => true,
                       :length => {:within => 8..25}
  validates :email, :presence => true,
                    :uniqueness => true,
                    :format => EMAIL_REGEX

  validates :password, :length => {:within => 8..25}

  validates :password_confirmation, :presence => true

  def send_password_reset
    generate_token(:password_reset_token)
    self.password_reset_sent_at = Time.zone.now
    save!
    UserMailer.password_reset(self).deliver
  end


  def generate_token(column)
    begin
      self[column] = SecureRandom.urlsafe_base64
    end while User.exists?(column => self[column])
  end


end

The error is shown at save! in send_password_reset. I am attaching an image.

enter image description here

I know the problem can be solved by using :on=>:create for validations as :update request is taking place. But when I get confirmation link in my console and use it, the validations for password and password_confirmation dont work as the action here is :update. This is like a deadlock.

I am really grateful to anyone who help me out from this maze.

Thank you.


Solution

  • You can Skip Validations using following eg.

    def send_password_reset
      generate_token(:password_reset_token) 
      self.password_reset_sent_at = Time.zone.now
      self.save(validate: false)
      UserMailer.password_reset(self).deliver
    end