仅允许Rails强参数中的某些可能值

Eph*_*aim 6 validation ruby-on-rails strong-parameters ruby-on-rails-4.2

我有一个带有用户模型的rails应用程序,它可以有多个角色.我使用像这样的位掩码实现了这个:

class User < ActiveRecord::Base
  DEFAULT_ROLES = %w[developer entrepreneur]
  ROLES = ['admin', 'entrepreneur', 'developer']

  def has_role?(role)
    roles.include?(role.to_s)
  end

  def is?(role)
    has_role?(role)
  end

  def roles=(roles)
    self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
  end

  def roles
    ROLES.reject do |r|
      ((roles_mask.to_i || 0) & 2**ROLES.index(r)).zero?
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

在应用的注册页面中,我希望用户选择他们是"企业家"还是"开发者".但是,我想确保他们无法为自己(或任何其他人)分配任何其他角色,除非他们已经是管理员.

我的第一个想法是在roles=方法中通过改变它看起来像这样做

  def roles=(roles)
    unless current_user.is?(:admin)
      validates_inclusion_of roles, :in => DEFAULT_ROLES
     end
    self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
  end
Run Code Online (Sandbox Code Playgroud)

但是,正如我发现的那样,你无法current_user从模型内部进行访问(如果你考虑它我觉得有意义......)

我的下一次尝试是看看我是否可以使用强参数来做到这一点.

我期待它看起来像这样(我正在使用设计,覆盖RegistrationsController)

class RegistrationsController < Devise::RegistrationsController

  private
  def sign_up_params
    if (user_signed_in?) && (current_user.is?(:admin))
      params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, {roles: User::ROLES})
    else 
      params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, {roles: User::DEFAULT_ROLES})
    end
  end

  def account_update_params
    if (user_signed_in?) && (current_user.is?(:admin))
      params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password, :about_me, {roles: User::ROLES})
    else
      params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试这个时,我得到了这个:在此输入图像描述 这让我觉得我误解了强参数的真正作用.

是否可以根据用户在强参数中的角色来限制用户可以为任何给定字段输入的值?如果没有,是否有不同的方法来实现这一目标?

Eph*_*aim 6

我想通了,这就是我做到的.(这是方法重写Devise的RegistrationController,如果你没有使用设计,那么只需替换任何方法控制输入新用户的参数.)

class RegistrationsController < Devise::RegistrationsController

 private
  def sign_up_params
    parameters = params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :about_me, roles: [])
    unless (user_signed_in?) && (current_user.is?(:admin))
      parameters[:roles] = parameters[:roles].reject { |h| !User::DEFAULT_ROLES.include? h }
      parameters
    end
  end


  def account_update_params
    if can? :assign_roles, :all
      params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password, :about_me, roles: [])
    else
      params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password)
    end
  end

end
Run Code Online (Sandbox Code Playgroud)

我只是将参数[:roles]中的参数过滤掉,只包含User::DEFAULT_ROLES(包含在问题中的上面所示)中的值,然后返回该parameters对象.