6
votes

So there doesn't appear to be any clean way to generically allow Hash field with strong parameters. This may of course be a strong parameters issue but I'm curious if there is a workaround. I have a model with some fields...

field :name, type: String
field :email, type: String
field :other_stuff, type: Hash, default: {}

Now I could just permit everything:

params.require(:registration).permit!

But that isn't really a great idea and what I'd like to do is something like...

params.require(:registration).permit(:name, :email, { other_stuff: {} })

However this doesn't seem to be possible with strong parameters, it isn't possible to just whitelist a hash as a property (yay for SQL centric ActiveRecord APIs!). Any ideas how this might be done, or is my best bet to submit a Rails patch to allow for this scenario.

3

3 Answers

8
votes

Ok, after researching this, I found an elegant solution that I will start using too:

params.require(:registration).permit(:name).tap do |whitelisted|
  whitelisted[:other_stuff] = params[:registration][:other_stuff]
end

source: https://github.com/rails/rails/issues/9454#issuecomment-14167664

0
votes

If necessary nested attributes can also be permitted as follows:

def create_params
  params[:book]["chapter"].permit(:content)
end
0
votes

For a field that allows nested hashes, I use the following solution:

def permit_recursive_params(params)
  params.map do |key, value|
    if value.is_a?(Array)
      { key => [ permit_recursive_params(value.first) ] }
    elsif value.is_a?(Hash) || value.is_a?(ActionController::Parameters)
      { key => permit_recursive_params(value) }
    else
      key
    end
  end
end

To apply it to for example the values param, you can use it like this:

def item_params
  params.require(:item).permit(values: permit_recursive_params(params[:item][:values]))
end