Search code examples
ruby-on-railspasswordspinterest

Rails Password Change


I'll start by telling you how I want my settings page set up.

I want users to be able to change their settings without requiring a password, and that's how it is set up now with this as the user model

validates :password, presence: true, length: { minimum: 6 }, :on => :create
validates :password_confirmation, presence: true, :on => :update, :unless => lambda{ |user| user.password.blank? }

This makes it so user's can change all of their settings without requiring a password (I know some might frown on this). But i want users to be able to change their passwords on the page like so...User clicks Change Password, a modal pops up, and users have to give their current password and then the new password and a confirmation of the new one. (I know how to do modal, i just want to know how do password reset).

Does this make sense?? I believe the way Pinterest does it is a good example (although they use Python I think)


Solution

  • My suggestion is to use a form object:

    app/forms/change_password_form.rb

    class ChangePasswordForm
      extend ActiveModel::Naming
      include ActiveModel::Conversion
      include ActiveModel::Validations
    
      # Add all validations you need
      validates_presence_of :old_password, :password, :password_confirmation
      validates_confirmation_of :password
      validate :verify_old_password
    
      attr_accessor :old_password, :password, :password_confirmation
    
      def initialize(user)
        @user = user
      end
    
      def submit(params)
        self.old_password = params[:old_pasword]
        self.password = params[:password]
        self.password_confirmation = params[:password_confirmation]
    
        if valid?
          @user.password = password
          @user.password_confirmation = password_confirmation
          @user.save!
          true
        else
          false
        end
      end
    
      def verify_old_password
        self.errors << "Not valid" if @user.password != password
      end
    
      # This method is required
      def persisted?
        false
      end
    end
    

    In controller initialize the form object @pass_form = ChangePasswordForm.new(current_user) and use the object in your modal: form_for @pass_form... and add the old_password, password and password_confirmation fields.

    And finally, for example, in the update action:

    @pass_form = ChangePasswordForm.new(current_user)
    
    if @pass_form.submit(params[:change_password_form])
      redirect_to some_path
    else
      render 'new'
    end
    

    I haven't tested this code, but you get the idea. Take a look to this Railscasts.