Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allowing only certain values though a strong parameter in Rails 4

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

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

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

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

I have the following code in a params method specific to an update in the controller before the params.require .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...

This works. A Sys admin user can not set otp_set_up to "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.

Is there a better / cleaner way?

like image 280
Iain Avatar asked Aug 01 '17 13:08

Iain


People also ask

What is strong parameters in Rails?

Strong Parameters, aka Strong Params, are used in many Rails applications to increase the security of data sent through forms. Strong Params allow developers to specify in the controller which parameters are accepted and used.

What does params permit do in Rails?

The permit method returns a copy of the parameters object, returning only the permitted keys and values.

What is params hash in Rails?

Specifically, params refers to the parameters being passed to the controller via a GET or POST request. In a GET request, params get passed to the controller from the URL in the user's browser.

What is params ID in Rails?

params[:id] is meant to be the string that uniquely identifies a (RESTful) resource within your Rails application. It is found in the URL after the resource's name.


1 Answers

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

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.

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

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.

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!

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

like image 154
m. simon borg Avatar answered Oct 20 '22 04:10

m. simon borg