通过 Rails 中的强参数仅允许某些值 4

Allowing only certain values though a strong parameter in Rails 4

我有一个字段otp_set_up,在company_user模型中允许"true" 或 "false".

有一个用例,系统管理员用户可以将此字段重置为 "false"。

虽然可以通过代码将字段设置为 "true",但用户不能通过表单编辑等将其设置为 "true"。

我没有在模型中添加验证,因为它可以是 "true" 或 "false"。

在 params.require .permit 位之前,我在特定于控制器更新的参数方法中有以下代码:

if curr_company_user.is_sys_admin? && curr_company_user.can_crud_company_users? && params[:id].to_i != curr_company_user.id

  params[:company_user] = params[:company_user].except(:otp_set_up) if params[:company_user][:otp_set_up] == true
  params.require(:company_user).permit(:otp_setup, etc. etc....

elsif etc. etc...

这行得通。系统管理员用户无法将 otp_set_up 设置为 "true"。

我的问题是:

这是在 Rails 中执行此操作的最佳和正确方法吗?对我来说似乎有点 hacky,通过 params 散列并删除一点。

有没有更好/更干净的方法?

我建议您仅在用户是管理员时才在参数中设置它,否则不要设置。我认为这是一个更好的方法。

在模型中,执行如下操作:

if user.role == 'admin'
  attr_accessor #All the params
else
  attr_accessor #All the other params except the one you want to 
  exclude

delete_if 清理它。仍然有点老套,但稍微不那么老套了:)

params.require(:company_user).permit(:otp_setup).delete_if do |key, val|
  key == 'otp_setup' && val == true
end

这会使原始 params 对象完好无损。

没有内置的方法来执行此操作。以前好像有,现在没有了https://github.com/rails/strong_parameters/issues/167

delete_if 是在核心库中的 Hash 上定义的,因此它可能是在 Ruby 中进行此操作的最佳方法,并在 Rails 中进行扩展缺少内置方法。

更新

我认为这是一个有趣的想法,所以我为这种类型的用例写了一个名为 allowable 的小 gem。它将在 HashActionController::Parameters 中添加一些方法:#allow#allow!#forbid#forbid!

你会像这样使用它

params.require(:company_user).permit(:otp_setup).forbid(otp_setup: [true])

# or

params.require(:company_user).permit(:otp_setup).allow(otp_setup: [false])

您可以指定单个值或值数组,它不会改变原始 params 对象

我真的不建议在这种情况下摆弄 params 对象。我认为最好让大部分内容保持不变,以保留实际要求的内容。这样,如果您在下游某处再次需要该值,您就不会挠头。

另一种方法是在传递到 permit 之前构建要接受的属性列表。

# Attributes that everyone can modify.
attrs = [:attrs, :everyone, :can, :modify]

# Then "whitelist" other attributes based on your permission logic.
if curr_company_user.is_sys_admin? && curr_company_user.can_crud_company_users? && params[:id].to_i != curr_company_user.id
  attrs << :otp_set_up unless params[:company_user][:otp_set_up] == true
elsif something_else?
  # Modify what can be permitted for this case.
  # etc...
end

params.require(:company_user).permit(*attrs)