Rails 4.2.7&设计4.1.1 - 使用AJAX

时间:2016-09-13 03:05:30

标签: ruby-on-rails ajax devise

我的应用有三种不同的用户类型(即设计模型):SuperAdminUserAdminUserStandardUser。每个用户,无论何种类型,都有一个首选项页面,他们可以在其中更新多个属性(例如:email:password:username等),其中两个属性要求用户输入其当前密码以进行更新(:email:password)的属性,而其余属性不需要更新当前密码。

现在,在我的理想世界中,首选项更新将使用AJAX,以便只更改的属性将在页面中刷新而不是整个页面重新加载。目前,我的这项功能适用于不要求用户输入当前密码的所有属性,但我无法使用:email:password 。奇怪的是,我让它在以前的原型中工作,但是只有一个Devise用户模型,而不是三个,并且单个模型没有它自己的注册控制器覆盖Devise注册控制器,当前应用程序中有三个用户模型,但我在这些重写注册控制器中看不到会影响此问题的任何内容。

我收到的唯一错误消息是我自己的,在首选项页面上:

Sorry, but we were unable to update your password.

问题似乎是没有从表单中捕获:current_password参数值。控制台日志语句将其显示为空字符串,同时捕获:new_password:new_password_confirmation值没有问题。我还没能确定为什么会这样。作为一种替代方法,我也尝试尽可能地模仿Devise wiki中的更改密码示例(最后一个示例)(此处:https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password),但无济于事。任何建议将不胜感激。

此外,我想要问的一个重要问题是我是否应该使用带密码属性的AJAX。也就是说,通过AJAX传递这些密码值本质上是不安全的吗?如果是这样,有没有办法安全地(例如加密)?

以下是我的相关代码:

应用/控制器/ 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, but we were unable to update your password.'
    end
    respond_to do |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

应用/视图/ super_admin_users /偏好/口令/ _change_password_form.html.haml

= form_tag super_admin_user_prefs_change_password_path, id: 'prefs-change-password-form' do
  .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'

应用/视图/ super_admin_users /偏好/口令/ _change_password_status_message.html.haml

#prefs-change-password-status-message.prefs-status-message= change_password_status_message

应用/视图/ super_admin_users /偏好/口令/ _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

应用/视图/ super_admin_users /偏好/口令/ 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');

应用/控制器/ application_controller.rb

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  include ApplicationHelper
  include DeviseParamSanitizerOverrides

  def get_current_user_type
    respond_to do |format|
      format.json { render json: { current_user_type: resource_name.to_s } }
    end
  end

  def get_current_environment
     respond_to do |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

应用/控制器/关切/ 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

应用/助手/ 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

应用/资产/ Javascript角/ 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() +
                                                                          '&current_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 Get Current User Type Error');
    }
  })
}

function getCurrentEnvironment(url) {
  return $.ajax({
    url: url,
    type: 'get',
    dataType: 'json'
  })
  .fail(function() {
    alert('AJAX Get Current Environment Error');
  })
}

function changePassword(url) {
  return $.ajax({
    url: url,
    type: 'get',
    dataType: 'json'
  })
  .fail(function() {
    if (currentEnvironment === 'development') {
      alert('AJAX Change Password Error');
    }
  })
}

配置/ routes.rb中

Rails.application.routes.draw do

  get '/get_current_user_type',   to: 'application#get_current_user_type'
  get '/get_current_environment', to: 'application#get_current_environment'
  .
  .
  .
  devise_for :super_admin_users, controllers: { registrations: 'super_admin_users/registrations' }

  authenticated :super_admin_user do
    root to: 'super_admin_users/dashboard#index', as: 'authenticated_super_admin_user_root'
  end

  as :super_admin_user do
    get  'super_admin_users/preferences/password_section_partial', to: 'super_admin_users/preferences#password_section_partial',
                                                                   as: :super_admin_user_password_section_partial
    get  'super_admin_users/preferences/change_password',          to: 'super_admin_users/preferences#change_password',
                                                                   as: :super_admin_user_prefs_change_password
  end

end

0 个答案:

没有答案