【问题标题】:Devise and StrongParams - undefined method permit for nil:NilClass设计和 StrongParams - nil:NilClass 的未定义方法允许
【发布时间】:2014-01-29 09:05:23
【问题描述】:

我目前使用 Rails 4,并将应用程序从 attr_accessible 移动到 StrongParams。所以,我已经定制了设计控制器:

class UsersController < Devise::RegistrationsController
  load_and_authorize_resource

  #...

  def update
    unless @user.userable?
      if params[:selected_person_type] ==  I18n::t('activerecord.attributes.user.individual')
        redirect_to new_individual_path and return
      elsif params[:selected_person_type] == I18n::t('activerecord.attributes.user.legal_entity')
        redirect_to new_legal_entity_path and return
      end
    end

    @avatar = params[:avatar_id].present? ? Avatar.find_by(id: params[:avatar_id]) : @user.avatar

    if params[:user][:password].blank?
      if @user.update_without_password(user_params)
        notice = if @user.unconfirmed_email.present? && Date.today == @user.confirmation_sent_at.to_date
          t('devise.confirmations.send_instructions')
        else
          t('views.messages.notices.personal_data_updated')
        end
        redirect_to edit_user_path(@user), notice: notice and return
      end
    else
      if @user.valid_password?(params[:user][:current_password])
        params[:user].delete("current_password")
        if @user.update_attributes(user_params) && @user.save
          sign_in(@user, bypass: true)
          redirect_to edit_user_path(@user), notice: t('views.messages.notices.personal_data_updated') and return
        end
      else
        @user.errors.add(:current_password, :invalid)
      end
    end

    render action: "edit"
  end

  def create
    if resource.save
      SystemMailer.send_mail(to: resource.email, body: resource.temp_password, subject: I18n.t('mailers.password.new')).deliver if resource.generate_password == '1'

      if request.xhr?
        expire_data_after_sign_in!
        respond_to do |format|
          format.js
        end
      else
        super
      end
    else
      if request.xhr?
        clean_up_passwords(resource)
        respond_to do |format|
          format.js
        end
      else
        super
      end
    end
  end

  private

  def user_params
    if current_user.present?
      params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
    end
  end
end

我之前得到了错误:

Failure/Error: post :create, user: attributes_for(:unconfirmed_user)
     ActiveModel::ForbiddenAttributesError:
       ActiveModel::ForbiddenAttributesError

这是因为 CanCan 与 StrongParams 不太兼容,所以我在 ApplicationController 中尝试了这个修复:

class ApplicationController < ActionController::Base
  include SimpleCaptcha::ControllerHelpers
  include CaptchaHelper

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

  before_filter :cancan_workaround

  rescue_from CanCan::AccessDenied do |e|
    redirect_to '/', flash: { error: I18n.t('views.messages.notices.access_denied') }
  end

  private

  def cancan_workaround
    resource = controller_name.singularize.to_sym
    method = "#{resource}_params"
    params[resource] &&= send(method) if respond_to?(method, true)
  end
end

修复后我得到了那个错误:

UsersController should successfully create user
     Failure/Error: post :create, user: attributes_for(:unconfirmed_user)
     NoMethodError:
       undefined method `permit' for nil:NilClass
     # ./app/controllers/users_controller.rb:75:in 'create'
     # ./spec/controllers/users_controller_spec.rb:10:in `block (3 levels) in <top (required)>'
     # ./spec/controllers/users_controller_spec.rb:9:in `block (2 levels) in <top (required)>'

这里是./app/controllers/users_controller.rb:75:in 'create'super 调用动作。知道如何解决这个问题吗?

【问题讨论】:

    标签: ruby-on-rails devise ruby-on-rails-4 cancan strong-parameters


    【解决方案1】:

    设计

    Devise 不像其他 Rails 输入系统那样工作 - 它使用自己的后端功能来处理参数。似乎设计自动允许emailpassword 参数,您的工作是添加其他参数parameter_sanitizer

    Devise and Strong Parameters

    底线是,根据Devise documentation,你必须使用这样的东西:

    #app/controllers/application_controller.rb
    class ApplicationController < ActionController::Base
      before_filter :configure_permitted_parameters, if: :devise_controller?
    
      protected
    
      def configure_permitted_parameters
        devise_parameter_sanitizer.for(:sign_up) << :username
      end
    end
    

    【讨论】:

      【解决方案2】:

      好的,我明白了。问题不在设计中,而是我的权限:

        private
      
        def user_params
          if current_user.present?
            params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
          end
        end
      

      测试为非签名用户评估,所以当cancan的钩子试图执行这个方法时:

      params[resource] &&= send(method) if respond_to?(method, true)
      

      它收到 nil,因为用户没有登录,所以挂钩将 :user =&gt; { ... } 转换为 :user =&gt; nil。所以,我通过删除 current_user.present? 来修复它。

        private
      
        def user_params
          params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
        end
      

      不确定此解决方案的安全性如何。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-11
        • 1970-01-01
        • 2017-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-27
        • 2013-06-30
        相关资源
        最近更新 更多