Rails 4.2.7 & Devise 4.1.1 - Change password with current password required in user preferences page with AJAX -
my application has 3 different user types (i.e. devise models): superadminuser
, adminuser
, standarduser
. every user, regardless of type, has preferences page able update number of attributes (e.g. :email
, :password
, :username
, etc.), 2 of attributes requiring user enter current password update (:email
, :password
), while remaining attributes not require current password update.
now, in ideal world, preference updates utilize ajax attribute changed refresh in page rather entire page reload. have working of attributes don't require user enter current password, i've been unable work :email
, :password
. oddly enough, have working in previous prototype, had 1 devise user model, not three, , single model didn't have it's own registration controller overriding devise registration controller, 3 user models in current app do, although don't see in these overriding registration controllers impacting issue here.
the error message i'm getting own, on preferences page:
sorry, unable update password.
the problem appears :current_password
param value not being captured form. console log statement shows blank string, while :new_password
, :new_password_confirmation
values captured without problem. haven't been able determine why happening. alternate approach, tried mimic closely change password example in devise wiki (the last example) (here: https://github.com/plataformatec/devise/wiki/how-to:-allow-users-to-edit-their-password), no avail. suggestions appreciated.
additionally, guess important question ask if should using ajax password attribute. is, inherently insecure passing these password values via ajax? if so, there way securely (e.g. encrypted)?
here relevant code:
app/controllers/super_admin_users/preferences_controller.rb
class superadminusers::preferencescontroller < applicationcontroller include applicationhelper before_action :authenticate_super_admin_user! . . . def change_password @super_admin_user = superadminuser.find_by(id: current_super_admin_user.id) if resource.update_with_password(params.permit(:password, :password_confirmation, :current_password)) sign_in resource_name, self.resource, bypass: true status_message = 'your password has been updated successfully!' else status_message = 'sorry, unable update password.' end respond_to |format| format.json { render json: { status_message: status_message } } end end def password_section_partial @change_password_status_message = params[:change_password_status_message] || "" render 'super_admin_users/preferences/password/password_section_partial' end . . . end end
app/views/super_admin_users/preferences/password/_change_password_form.html.haml
= form_tag super_admin_user_prefs_change_password_path, id: 'prefs-change-password-form' .prefs-label-and-input-wrapper #prefs-new-password-label-wrapper.prefs-input-label-wrapper = label_tag 'password', 'new password', id: 'prefs-new-password-label', class: 'prefs-input-label' #prefs-new-password-input-wrapper.prefs-input-wrapper = password_field_tag 'password', nil, autofocus: true, autocomplete: 'off', id: 'prefs-new-password-input', class: 'prefs-input' .prefs-label-and-input-wrapper #prefs-new-password-confirmation-label-wrapper.prefs-input-label-wrapper = label_tag 'password_confirmation', 'new password confirmation', id: 'prefs-new-confirmation-password-label', class: 'prefs-input-label' #prefs-new-password-confirmation-input-wrapper.prefs-input-wrapper = password_field_tag 'password_confirmation', nil, autocomplete: 'off', id: 'prefs-new-password-confirmation-input', class: 'prefs-input' .prefs-label-and-input-wrapper #prefs-current-password-label-wrapper.prefs-input-label-wrapper = label_tag 'current_password', 'current password', id: 'prefs-current-password-label', class: 'prefs-input-label' #prefs-current-password-input-wrapper.prefs-input-wrapper = password_field_tag 'current_password', nil, autocomplete: 'off', id: 'prefs-current-password-input', class: 'prefs-input' #prefs-change-password-form-buttons-wrapper #prefs-change-password-form-submit-btn-wrapper = link_to 'update', 'javascript:;', id: 'prefs-change-password-form-submit-btn', class: 'btn btn-sm btn-success btn-submit' -#%input{ id: 'prefs-change-password-form-submit-btn', class: 'btn btn-sm btn-success', type: 'submit', value: 'update' } #prefs-change-password-form-cancel-btn-wrapper = link_to 'cancel', 'javascript:;', id: 'prefs-change-password-form-cancel-btn', class: 'btn btn-sm btn-secondary btn-cancel'
app/views/super_admin_users/preferences/password/_change_password_status_message.html.haml
#prefs-change-password-status-message.prefs-status-message= change_password_status_message
app/views/super_admin_users/preferences/password/_password_section.html.haml
#prefs-password-section-header.prefs-section-header #prefs-password-headline-wrapper .prefs-section-headline password #prefs-password-edit-btn-wrapper = link_to 'edit', 'javascript:;', id: 'prefs-password-edit-btn', class: 'btn btn-sm btn-primary btn-edit' #prefs-change-password-form-wrapper.prefs-form-wrapper.no-display = render partial: 'super_admin_users/preferences/password/change_password_form' #prefs-change-password-status-message-wrapper.prefs-status-message-wrapper.no-display
app/views/super_admin_users/preferences/password/password_section_partial.js.haml
$('#prefs-change-password-status-message-wrapper').empty(); $('#prefs-change-password-form-wrapper').addclass('no-display'); $('#prefs-change-password-form').trigger('reset'); - if @change_password_status_message.present? $('#prefs-change-password-status-message-wrapper').append("#{ escape_javascript(render(partial: 'super_admin_users/preferences/password/change_password_status_message', locals: { change_password_status_message: @change_password_status_message })) }"); $('#prefs-change-password-status-message-wrapper').removeclass('no-display'); $('#prefs-password-edit-btn').removeclass('no-display');
app/controllers/application_controller.rb
class applicationcontroller < actioncontroller::base # prevent csrf attacks raising exception. # apis, may want use :null_session instead. protect_from_forgery with: :exception include applicationhelper include deviseparamsanitizeroverrides def get_current_user_type respond_to |format| format.json { render json: { current_user_type: resource_name.to_s } } end end def get_current_environment respond_to |format| format.json { render json: { current_environment: rails.env } } end end protected def devise_parameter_sanitizer if resource_class.to_s == 'superadminuser' superadminuser::parametersanitizer.new(superadminuser, :super_admin_user, params) elsif resource_class.to_s == 'adminuser' adminuser::parametersanitizer.new(adminuser, :admin_user, params) elsif resource_class.to_s == 'standarduser' standarduser::parametersanitizer.new(standarduser, :standard_user, params) end end end
app/controllers/concerns/devise_param_sanitizer_overrides.rb
module deviseparamsanitizeroverrides extend activesupport::concern class superadminuser::parametersanitizer < devise::parametersanitizer def initialize(*) super permit(:sign_up, keys: [:email, :first_name, :last_name, :username]) permit(:sign_in, keys: [:email, :username]) permit(:account_update, keys: [:current_password, :email, :first_name, :last_name, :time_zone, :username]) end end . . . end
app/helpers/application_helper.rb
module applicationhelper def resource if super_admin_user_signed_in? @super_admin_user ||= superadminuser.new elsif admin_user_signed_in? @admin_user ||= adminuser.new elsif standard_user_signed_in? @standard_user ||= standarduser.new end end def resource_name if super_admin_user_signed_in? :super_admin_user elsif admin_user_signed_in? :admin_user elsif standard_user_signed_in? :standard_user end end def resource_class if super_admin_user_signed_in? superadminuser elsif admin_user_signed_in? adminuser elsif standard_user_signed_in? standarduser end end def devise_mapping if super_admin_user_signed_in? @devise_mapping ||= devise.mappings[:super_admin_user] elsif admin_user_signed_in? @devise_mapping ||= devise.mappings[:admin_user] elsif standard_user_signed_in? @devise_mapping ||= devise.mappings[:standard_user] end end def resource_authenticated_root if super_admin_user_signed_in? authenticated_super_admin_user_root elsif admin_user_signed_in? authenticated_admin_user_root elsif standard_user_signed_in? authenticated_standard_user_root end end end
app/assets/javascripts/preferences.js
var currentusertype; var currentenvironment; getcurrentusertype('/get_current_user_type' ).done(function(getcurrentusertyperesponse) { currentusertype = getcurrentusertyperesponse.current_user_type; }); getcurrentenvironment('/get_current_environment' ).done(function(getcurrentenvironmentresponse) { currentenvironment = getcurrentenvironmentresponse.current_environment; }); $(document).ready(function() { $('#prefs-password-edit-btn').click(function (e) { $('#prefs-password-edit-btn').addclass('no-display'); $('#prefs-change-password-form').trigger('reset'); $('#prefs-change-password-form-wrapper').removeclass('no-display'); }); $(function() { return $('body').on('click', '#prefs-change-password-form-submit-btn', function() { $('#prefs-change-password-form-wrapper').addclass('no-display'); changepassword('/' + currentusertype + 's/preferences/change_password?password=' + $('#prefs-new-password-input').val() + '&password_confirmation=' + $('#prefs-new-password-confirmation-input').val() + '¤t_password=' + $('#prefs-current-password-input').val() ).done(function(changepasswordresponse) { $.ajax({url: '/' + currentusertype + 's/preferences/password_section_partial?change_password_status_message=' + changepasswordresponse.status_message}); }); }); }); $(function() { return $('body').on('click', '#prefs-change-password-form-cancel-btn', function() { $('#prefs-change-password-form-wrapper').addclass('no-display'); $('#prefs-change-password-form').trigger('reset'); $('#prefs-password-edit-btn').removeclass('no-display'); }); }); function getcurrentusertype(url) { return $.ajax({ url: url, type: 'get', datatype: 'json' }) .fail(function() { if (currentenvironment === 'development') { alert('ajax current user type error'); } }) } function getcurrentenvironment(url) { return $.ajax({ url: url, type: 'get', datatype: 'json' }) .fail(function() { alert('ajax current environment error'); }) } function changepassword(url) { return $.ajax({ url: url, type: 'get', datatype: 'json' }) .fail(function() { if (currentenvironment === 'development') { alert('ajax change password error'); } }) }
config/routes.rb
rails.application.routes.draw '/get_current_user_type', to: 'application#get_current_user_type' '/get_current_environment', to: 'application#get_current_environment' . . . devise_for :super_admin_users, controllers: { registrations: 'super_admin_users/registrations' } authenticated :super_admin_user root to: 'super_admin_users/dashboard#index', as: 'authenticated_super_admin_user_root' end :super_admin_user 'super_admin_users/preferences/password_section_partial', to: 'super_admin_users/preferences#password_section_partial', as: :super_admin_user_password_section_partial 'super_admin_users/preferences/change_password', to: 'super_admin_users/preferences#change_password', as: :super_admin_user_prefs_change_password end end
Comments
Post a Comment