vendredi 1 janvier 2016

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 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.

Aucun commentaire:

Enregistrer un commentaire