30

I have this in my controller:

params.require(:item).permit!

Let's assume this rspec spec, which works as expected:

put :update, id: @item.id, item: { name: "new name" }

However, the following causes ActionController::ParameterMissing:

put :update, id: @item.id, item: nil

It has to do with controller macros that I use for other actions and through which I cannot control the params being sent (the macros checks for user credentials, so I don't really care about actually testing an #update action, rather I just test before_filters for it).

So my question is: How do I make params[:item] optional, yet still filter attributes within it if it's present?

Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
orion3
  • 9,797
  • 14
  • 67
  • 93
  • 5
    Some good ideas at https://github.com/rails/rails/issues/9534 . Basically the suggestion is to use `#fetch` instead of `#require` since it has a second parameter for a default, e.g.: `params.fetch(:item, {}).permit!`. – mtjhax Jul 03 '15 at 16:48

1 Answers1

52

What about:

params.require(:item).permit! if params[:item]

You cannot require an optional parameter. That is contradictory.

Edit: as mtjhax mentioned in his comment, there is advice from here to use fetch instead: params.fetch(:item, {}).permit!

Damien Roche
  • 13,189
  • 18
  • 68
  • 96
  • 1
    I think you misunderstood his question. It's perfectly valid to want to require the main container (:item) while making some of its internal sub-attributes optional only, which aside from using `params.require(:item).permit!` (which permits any parameters as long as they're within `:item` and `:item` exists doesn't seem possible in a granular way. – Olivier Lacan Jul 06 '14 at 00:34
  • @OlivierLacan reading it back, I think you might be correct, though I'm now confused why he accepted my answer if it didn't resolve his problem. – Damien Roche Jul 06 '14 at 11:54
  • `params.require(:item).permit! if params[:item]` does not work as it doesn't drill down into the `:item` hash and can't be passed into `new` for instance. `fetch(...)` works like a charm. – Christopher Oezbek Feb 22 '21 at 09:56