带有清除的ForbiddenAttributesError

时间:2017-09-28 14:13:49

标签: ruby-on-rails clearance

我正在使用许可进行注册,并且除了电子邮件和密码之外还有一些额外的属性,这些属性包括first_name,last_name,role和university,条件是如果角色是职员。

我有三个用户角色:

  enum role: { staff: 0, clinician: 1, admin: 2 }

我的实现出了问题,因为注册尝试会导致以下错误:

ActiveModel::ForbiddenAttributesError in Clearance::UsersController#create

将此行代码突出显示为违规行:

 Clearance.configuration.user_model.new(user_params).tap do |user|

我做错了什么?任何帮助将不胜感激。

这是我的整个app / clearance / users_controller.rb

class Clearance::UsersController < Clearance::BaseController
  if respond_to?(:before_action)
    before_action :redirect_signed_in_users, only: [:create, :new]
    skip_before_action :require_login, only: [:create, :new], raise: false
    skip_before_action :authorize, only: [:create, :new], raise: false
  else
    before_filter :redirect_signed_in_users, only: [:create, :new]
    skip_before_filter :require_login, only: [:create, :new], raise: false
    skip_before_filter :authorize, only: [:create, :new], raise: false
  end
  layout 'authentication'

  def new
    @user = user_from_params
    render template: "users/new"
  end

  def create
    @user = user_from_params

    if @user.save
      case @user.role
      when "staff"
        validate_user(@user)
      when "clinician"
        user.update_attribute(:approved, true)
        deliver_email(@user)
      end
    else
      render template: "users/new"
    end
  end

  private

  def validate_user(user)
    if user.whitelisted?
      user.update_attribute(:approved, true)
      deliver_email(user)
    else
      redirect_to sign_in_path,
        notice: "Your request will be analyzed"
    end
  end

  def deliver_email(user)
    user.forgot_password! #Generates confirmation token only
    mail = ::ClearanceMailer.confirm_email(user)

    if mail.respond_to?(:deliver_later)
      mail.deliver_later
    else
      mail.deliver
    end
    redirect_to sign_in_path,
      notice: "Please confirm your email address."
  end

  def avoid_sign_in
    warn "[DEPRECATION] Clearance's `avoid_sign_in` before_filter is " +
      "deprecated. Use `redirect_signed_in_users` instead. " +
      "Be sure to update any instances of `skip_before_filter :avoid_sign_in`" +
      " or `skip_before_action :avoid_sign_in` as well"
    redirect_signed_in_users
  end

  def redirect_signed_in_users
    if signed_in?
      redirect_to Clearance.configuration.redirect_url
    end
  end

  def url_after_create
    Clearance.configuration.redirect_url
  end

def user_params
  params.require(:user).permit(
    :email, 
    :password, 
    :role, 
    :first_name, 
    :last_name, 
    :university_id
  )
end

    Clearance.configuration.user_model.new(user_params).tap do |user|
      user.email = email
      user.password = password
      user.role = role
      user.first_name = first_name
      user.last_name = last_name
      if role == "staff"
        user.university = University.find(university)
      end
    end
  end

  def user_params
    params[Clearance.configuration.user_parameter] || Hash.new
  end
end

2 个答案:

答案 0 :(得分:1)

清除被构建为可用于使用强参数的新版本的Rails和不使用的旧版本的Rails。这意味着此代码比期望的要复杂一些。 default implementation of user_from_params明确指定了电子邮件和密码,因此在使用attr_accessible或强参数时我们完全避免了批量分配。但是,我们还会将其余参数传递给使用Clearance.configuration.user_model.new(user_params)的用户模型。

而不是覆盖user_from_params,我会调查覆盖user_params,而是明确允许您允许的字段:

def user_params
  params.require(:user).permit(
    :email, 
    :password, 
    :role, 
    :first_name, 
    :last_name, 
    :university_id
  )
end

值得指出的是,像这样分配role实际上看起来像是一个群发分配漏洞。您允许用户选择其访问级别。如果这是某种可信赖的系统,这是可以的,那么我猜你采取的方法似乎很好。如果您依赖某些前端表单字段来限制谁可以注册每个角色...不要。

此方法应位于用户控制器内,该控制器应继承自Clearance::UsersController。您似乎已选择重新定义Clearance::UsersController。我建议您创建自己的UsersController,如下所示:

class UsersController < Clearance::UsersController
  layout "authentication"

  private

  def user_params
    params.require(:user).permit(
      :email, 
      :password, 
      :role, 
      :first_name, 
      :last_name, 
      :university_id
    )
  end
end

这没有您提交的控制器的用户验证逻辑。我尝试将其移至您的User模型。如果做不到这一点,您也可以覆盖控制器中的create

您需要确保您的路线文件指向UsersController而不是Clearance::UsersController

答案 1 :(得分:0)

问题在于您不断调用user_params,它会返回符号:user。你需要更像这样的东西来定位正确的参数:

def user_from_params

  email = params[:user].delete(:email)
  password = params[:user].delete(:password)
  role = params[:user].delete(:role)
  first_name = params[:user].delete(:first_name)
  last_name = params[:user].delete(:last_name)
  university_id = params[user].delete(:university_id)

  # and you can use whatever other params you sent with params[:user] here
  Clearance.configuration.user_model.new(params[:user]).tap do |user|
    user.email = email
    user.password = password
    user.role = role
    user.first_name = first_name
    user.last_name = last_name
    if role == "staff"
      user.university = University.find(university)
    end
  end
end