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

时间:2022-05-02 11:00:38

I have a field otp_set_up, which in the company_user model is allowed to be "true" or "false".

我有一个字段otp_set_up,在company_user模型中,允许它是“true”或“false”。

There is a use case where a sys admin user can reset this field to "false".

有一个用例,系统管理员可以将这个字段重置为“false”。

While the field can be set to "true" through code, NO user can set it to "true" via a form edit etc.

虽然可以通过代码将字段设置为“true”,但是没有用户可以通过表单编辑等方式将其设置为“true”。

I haven't added to it the validation in the model since it can be "true" or "false".

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

I have the following code in a params method specific to an update in the controller before the params.require .permit bit:

在params之前,我有一个params方法中特定于控制器更新的代码。需要.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...

This works. A Sys admin user can not set otp_set_up to "true".

这个作品。系统管理员用户不能将otp_set_up设置为“true”。

My question is:

我的问题是:

Is this the best and correct way to do this in Rails? It seems a bit hacky to me, going through the params hash and removing a bit.

在Rails中,这是最好和正确的方法吗?在我看来,这有点陈腐,通过帕拉姆斯哈希并删除一点。

Is there a better / cleaner way?

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

3 个解决方案

#1


3  

delete_if cleans it up. Still a bit hacky, but slightly less so : )

delete_if清洗。还是有点陈腐,但稍微不那么陈腐:

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

This leaves the original params object intact.

这将使原始的params对象保持完整。

There isn't a built in way to do this. It looks like there used to be but no more https://github.com/rails/strong_parameters/issues/167

没有一种内在的方法可以做到这一点。看起来好像曾经有过,但是现在没有了https://github.com/rails/strong_parameters/issues/167

delete_if is defined on Hash in the core library, so it is probably the best way to do it in Ruby and by extension in Rails in the absence of a built in method.

delete_if是在core库中的散列上定义的,因此在没有内置方法的情况下,它可能是在Ruby中以及在Rails中进行扩展的最佳方式。

Update

I thought it was an interesting idea, so I wrote a small gem called allowable for this type of use case. It will add a few methods to Hash and ActionController::Parameters: #allow, #allow!, #forbid and #forbid!

我认为这是一个有趣的想法,所以我为这种类型的用例写了一个小的gem,称为允许值。它将向Hash和ActionController添加一些方法::参数:#allow, #allow!,#禁止和#不容!

You would use it like this

你可以这样使用它

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

# or

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

You can specify a single value or an array of values, and it doesn't mutate the original params object

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

#2


0  

I don't really recommend messing around with the params object in this case. I think it's best to leave that untouched for the most part to preserve what was actually requested. That way you're not left scratching your head if you need that value again somewhere downstream.

我不建议在这种情况下使用params对象。我认为最好在大部分情况下保持原封不动,以保留实际需要的东西。这样你就不会在下游的某个地方需要那个值了。

Another approach is to build the list of attributes to accept before passing into 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)

#3


0  

I have a suggestion that you set it in the params only if the user is an admin and not otherwise. I think this is a better way.

我有一个建议,您应该只在用户是管理员时才将其设置在params中。我认为这是一种更好的方式。

In the model, do something like this:

在模型中,这样做:

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

#1


3  

delete_if cleans it up. Still a bit hacky, but slightly less so : )

delete_if清洗。还是有点陈腐,但稍微不那么陈腐:

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

This leaves the original params object intact.

这将使原始的params对象保持完整。

There isn't a built in way to do this. It looks like there used to be but no more https://github.com/rails/strong_parameters/issues/167

没有一种内在的方法可以做到这一点。看起来好像曾经有过,但是现在没有了https://github.com/rails/strong_parameters/issues/167

delete_if is defined on Hash in the core library, so it is probably the best way to do it in Ruby and by extension in Rails in the absence of a built in method.

delete_if是在core库中的散列上定义的,因此在没有内置方法的情况下,它可能是在Ruby中以及在Rails中进行扩展的最佳方式。

Update

I thought it was an interesting idea, so I wrote a small gem called allowable for this type of use case. It will add a few methods to Hash and ActionController::Parameters: #allow, #allow!, #forbid and #forbid!

我认为这是一个有趣的想法,所以我为这种类型的用例写了一个小的gem,称为允许值。它将向Hash和ActionController添加一些方法::参数:#allow, #allow!,#禁止和#不容!

You would use it like this

你可以这样使用它

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

# or

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

You can specify a single value or an array of values, and it doesn't mutate the original params object

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

#2


0  

I don't really recommend messing around with the params object in this case. I think it's best to leave that untouched for the most part to preserve what was actually requested. That way you're not left scratching your head if you need that value again somewhere downstream.

我不建议在这种情况下使用params对象。我认为最好在大部分情况下保持原封不动,以保留实际需要的东西。这样你就不会在下游的某个地方需要那个值了。

Another approach is to build the list of attributes to accept before passing into 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)

#3


0  

I have a suggestion that you set it in the params only if the user is an admin and not otherwise. I think this is a better way.

我有一个建议,您应该只在用户是管理员时才将其设置在params中。我认为这是一种更好的方式。

In the model, do something like this:

在模型中,这样做:

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