【问题标题】:Allowing only certain possible values in Rails Strong Parameters在 Rails 强参数中只允许某些可能的值
【发布时间】:2015-04-04 20:34:36
【问题描述】:

我有一个带有用户模型的 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

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

我的第一个想法是在 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

但是,正如我发现的那样,您无法从模型内部访问 current_user(如果您考虑一下,我想这是有道理的......)

我的下一个尝试是看看我是否可以使用 Strong Parameters 来做到这一点。

我期待它看起来像这样(我正在使用设计,覆盖 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

但是,当我尝试这样做时,我得到了这个: 这让我觉得我误解了强参数是如何真正起作用的。

是否可以根据用户的角色使用强参数来限制用户可以为任何给定字段输入的值?如果没有,有没有其他方法可以做到这一点?

【问题讨论】:

  • 应该定义为模型验证。强参数用于过滤参数键,而不是值。
  • @kengo - 如果我无法访问角色当前用户,如何在模型中验证它? (因为管理员可能正在修改其他用户,而不仅仅是他们自己)
  • 您不能将强参数定义为 before_action。在创建或更新方法中像这样使用。 Account.new(account_update_params)
  • 控制器(或多或少)决定谁可以做什么(以及执行特定操作后的去向)。 “你就是这种用户/那种用户,你能做到你要求的吗?”如果没有,请到这里。如果没问题,那么模型会负责验证输入以查看它是否是一组合法的值。控制器可以强制执行参数检查(如果当前用户是管理员,则在更新中允许角色的任何值,否则,从参数中删除该键/值。

标签: ruby-on-rails validation strong-parameters ruby-on-rails-4.2


【解决方案1】:

我想通了,这就是我的做法。 (这是覆盖 Devise 的 RegistrationController 的方法,如果您不使用 devise,则只需替换控制输入新用户的参数的任何方法。)

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

我刚刚过滤掉了parameters[:roles] 中的参数,只包含User::DEFAULT_ROLES 中包含的值(如上面的问题所示),然后返回parameters 对象。

【讨论】:

  • 是的,参数是可修改的(在我回复您之前,您已对其进行了排序)。
猜你喜欢
  • 2023-03-15
  • 2014-09-03
  • 1970-01-01
  • 2021-05-02
  • 2019-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多