Allowing only certain values, although a strong setting in Rails 4

I have an otp_set_up field which is allowed as "true" or "false" in the company_user model .

There is a precedent where the sys admin user can reset this field to "false".

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

I have not added a validation to it in the model as it can be true or false.

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

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...

      

It works. Sys user admin cannot set otp_set_up to "true".

My question is:

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

Is there a better / cleaner way?

+3


source to share


3 answers


delete_if

clears it. Still a little hacky, but a little less :)

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

      

This leaves the original object params

intact.

There is no built-in way to do this. Looks like it used to be, but no more https://github.com/rails/strong_parameters/issues/167

delete_if

is defined in Hash

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



Update

I thought this was an interesting idea, so I wrote a little gem called allowable for this type of use case. He adds a few methods to Hash

and ActionController::Parameters

: #allow

, #allow!

, #forbid

and#forbid!

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 not mutate the original object params

+3


source


I have a suggestion that you only set it in the options if the user is an administrator, not otherwise. I think this is the best way.

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

      

0


source


In this case, I really don't recommend messing with the object params

. I think it's best to leave this untouched for the most part in order to keep what was actually requested. This way, you won't be scratching your head if you need this information again somewhere downstream.

Another approach is to create a list of attributes to accept before going to 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)

      

0


source







All Articles