Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails hashes with unknown keys and strong parameters

I have a rails application that stores a serialized hash in a field called properties.

The hashes keys are unknown though, so I don't know of a way to allow this with strong parameters.

When googling, I found this: https://github.com/rails/rails/issues/9454, but I couldn't figure out exactly what a solution would be.

So basically, my question is: How can you configure strong parameters to allow hashes with unknown keys?

Thanks for all help!

like image 913
the_ Avatar asked Oct 04 '13 03:10

the_


3 Answers

I recently had this same issue and I solved it using @fxn's method from https://github.com/rails/rails/issues/9454

For product with properties as hash, solved it as

def product_params
  params.require(:product).permit(:title, :description).tap do |whitelisted|
    whitelisted[:properties] = params[:product][:properties]
  end
end

If you use :raise instead of :log for config.action_controller.action_on_unpermitted_parameters in your environment then remember to remove properties from params before calling permit. Then the method will be

def product_params
  properties = params[:product].delete(:properties)
  params.require(:product).permit(:title, :description).tap do |whitelisted|
    whitelisted[:properties] = properties
  end
end
like image 135
teknuk Avatar answered Nov 14 '22 23:11

teknuk


None of these answers worked for me (using Rails 4.2.4), so I figured out the following workaround:

def product_params properties_keys = params[:product][:properties].keys params.require(:product).permit(:title, :description, properties: properties_keys) end

Hope that helps someone.

like image 34
Chris W Avatar answered Nov 14 '22 23:11

Chris W


You can use a hash instead of a symbol and define what sub-properties are allowed. This can be seen in the source here:

case filter
when Symbol, String
  permitted_scalar_filter(params, filter)
when Hash
  hash_filter(params, filter)
end

https://github.com/rails/rails/blob/bdc73a438a97f2e0aceeb745f4a95f95514c4aa6/actionpack/lib/action_controller/metal/strong_parameters.rb#L522

e.g.

def user_params
  params.require(:person).permit(:name, :description, :age, properties: [:key, :value])
end

If you have no idea what is going to be in properties you could use .slice. Note this will accept anything nested in any of the other fields too.

e.g.

def user_params
  params.require(:person).slice(:name, :description, :age, :properties) 
end

These approaches will work on the following params:

{
  "person": {
    "name": "John",
    "description": "has custom_attributes",
    "age": 42,
    "properties": [
      {
        "key": "the key",
        "value": "the value"
      }
    ]
  }
}

I've confirmed these will work on Rails 4.2.6

like image 37
cianmce Avatar answered Nov 14 '22 23:11

cianmce