How to separate change password from devise form
Asked Answered
S

2

10

I am trying to do two things:

1) Change the default "edit user form" - provided with devise - to remove "password" and allow the other fields to be updated without having to enter a password ie remove the default validation for password.

2) Create a separate form for changing password

I have got everything to work, there is only one problem, in the separate form for updating password, I have included a field for current password. When using the form, no validation is made for current password, so I changed

@user.update_attributes(params[:user]) 

to

@user.update_with_password(params[:user])

This worked, however it raised another issue. Back in the main form with all the other details except password, the form now asks for a "current password". How can I achieve this without a validation for current password being called on the main form?

here is my registrations controller:

def update
  @user = User.find(current_user.id)
  if @user.update_attributes(params[:user])
    set_flash_message :notice, :updated
    # Sign in the user bypassing validation in case his password changed
    sign_in @user, :bypass => true
    redirect_to after_update_path_for(@user)
  else
    clean_up_passwords(resource)
    respond_with_navigational(resource) do
      if params[:change_password] # or flash[:change_password]
        render :change_password
      else
        render :edit
      end
    end
  end
end

Thanks!

Solution 1

I have found a solution to the problem (albeit a very messy one):

def update
  @user = User.find(current_user.id)

  if params[:user][:password].blank?
    if @user.update_attributes(params[:user])
      set_flash_message :notice, :updated
      # Sign in the user bypassing validation in case his password changed
      sign_in @user, :bypass => true
      redirect_to after_update_path_for(@user)
    else
      respond_with_navigational(resource) do
        render :edit
      end
    end
  else
    if @user.update_with_password(params[:user])
      set_flash_message :notice, :updated
      # Sign in the user bypassing validation in case his password changed
      sign_in @user, :bypass => true
      redirect_to after_update_path_for(@user)
    else
      clean_up_passwords(resource)
      respond_with_navigational(resource) do
        render :change_password
      end
    end
  end

Solution 2

Can you suggest a better solution?

Sarilda answered 11/7, 2013 at 4:8 Comment(0)
H
5

Did you bother to check out Devise wiki? There are examples for both this cases

  1. https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-account-without-providing-a-password
  2. https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password

You should be looking at @user.update_with_password(params[:user]) vs @user.update_attributes(params[:user])

Hibiscus answered 11/7, 2013 at 6:10 Comment(6)
Yes I have had a look at both, I don't see where they provide a solution to the issue? Can you please show me specifically?Sarilda
Copy&paste from my answer: You should be looking at @user.update_with_password(params[:user]) vs @user.update_attributes(params[:user])Hibiscus
Can you have a look at the edit I made to the question above^^ It works, but is that the best way of doing it?Sarilda
Why do you try deleting password hash key if it doesn't exist? (first 4 lines). And - is the rest of code the same for password change and other?Hibiscus
There's a lot of duplicated code, one solution I can think of is something like update_result = ( params[:user][:password].blank? ? @user.update_attributes(params[:user]) : @user.update_with_password(params[:user]) ) and then just check for false (that's the part that differs for both updates) but this is ugly like hell.Hibiscus
Also - do you need this if params[:change_password]? Users can still update both other options and password? If not you can remove it.Hibiscus
A
6

The accepted answer does not fully address the question. Which, I believe is to have a separate form for user profile attributes (like email, first name, etc) vs. the password. Here's what you need to do for that:

First, leverage the Devise::RegistrationsController for your profile updates.

  • Customize the view and remove the password and password_confirmation fields. Devise ignores these if they are not present in the put.
  • If you don't want to require the current password to make profile changes, read this. Not recommended; not secure.

Second, create your own controller to manage the password updates and your own helper to require current_password, password, and password_confirmation on update.

class PasswordsController < ApplicationController
  before_filter :authenticate_user!

  def edit
    @user = current_user
  end

  def update
    @user = User.find(current_user.id)
    if @user.update_password_with_password(user_params)
      # Sign in the user by passing validation in case their password changed
      sign_in @user, :bypass => true
      redirect_to edit_password_path, flash: { success: "Successfully updated password" }
    else
      render "edit"
    end

  end

  private

    def user_params
      params.require(:user).permit(:current_password, :password, :password_confirmation)
    end

end

Here's the helper, update_password_with_password that will require the new password fields.

class User < ActiveRecord::Base
  def update_password_with_password(params, *options)
    current_password = params.delete(:current_password)

    result = if valid_password?(current_password)
               update_attributes(params, *options)
             else
               self.assign_attributes(params, *options)
               self.valid?
               self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
               false
             end

    clean_up_passwords
    result
  end
end
Allamerican answered 8/8, 2015 at 3:20 Comment(2)
Im trying to follow this answer , im kind of a noob though, could you please add the routes , view and link_to that should be used with this solution ? thanks!Huebner
This answer implements the password change and profile change (without password) in a manner opposite to how the Devise wiki recommends. The link provided suggests creating a separate controller to edit non-critical user profile data that can safely be changed without providing a password. It also provides an alternative approach which is not recommended to follow. So I would say that the recommend approach would be to use the devise registrations controller to perform password and/or email edits and then provide a separate controller for editing fields that don't need a password.Matthaus
H
5

Did you bother to check out Devise wiki? There are examples for both this cases

  1. https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-account-without-providing-a-password
  2. https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password

You should be looking at @user.update_with_password(params[:user]) vs @user.update_attributes(params[:user])

Hibiscus answered 11/7, 2013 at 6:10 Comment(6)
Yes I have had a look at both, I don't see where they provide a solution to the issue? Can you please show me specifically?Sarilda
Copy&paste from my answer: You should be looking at @user.update_with_password(params[:user]) vs @user.update_attributes(params[:user])Hibiscus
Can you have a look at the edit I made to the question above^^ It works, but is that the best way of doing it?Sarilda
Why do you try deleting password hash key if it doesn't exist? (first 4 lines). And - is the rest of code the same for password change and other?Hibiscus
There's a lot of duplicated code, one solution I can think of is something like update_result = ( params[:user][:password].blank? ? @user.update_attributes(params[:user]) : @user.update_with_password(params[:user]) ) and then just check for false (that's the part that differs for both updates) but this is ugly like hell.Hibiscus
Also - do you need this if params[:change_password]? Users can still update both other options and password? If not you can remove it.Hibiscus

© 2022 - 2024 — McMap. All rights reserved.