5

There are a lot of questions about Nested Parameters, but I can't seem to find one that addresses my specific, simple situation.

I'm trying to permit a nested hash that is NOT an array. I expected this to work:

params.require(:book).permit(:title, :description, style: {:font, :color})

But it resulted in a syntax error.

This, however, worked:

params.require(:book).permit(:title, :description, style: [:font, :color])

But my issue with this, it it seems to permit style values that are arrays of items with attributes :font and :color. I only want to permit a single hash with those 2 attributes.

I've tried other variations, but I keep getting syntax errors. I'd appreciate any help with this.

Context: Rails 4.1.7, Ruby 2.0.0 (It's on my todo list to upgrade!), not using ActiveRecord.

readyornot
  • 2,783
  • 2
  • 19
  • 31

3 Answers3

10

The problem is that, as your error states, you have a syntax error. This is because {:font, :color} is not valid Ruby. You're attempting to mix the hash syntax, { key: value }, with the array syntax, [:one, :two]. What you're likely wanting to do is,

# Accept params: { book: { style: { font: value, color: value } } }
params.require(:book).permit(style: [:font, :color])

or,

# Accept params: { book: { style: [{ font: value, color: value }] } }
params.require(:book).permit(style: [[:font, :color]])

The fact that you're using an array of keys to accept a hash (not an array) is just how strong_parameters works. To accept an array, you would actually just do something like this,

# Accept params: { book: { style: [:font, :color] } }
params.require(:book).permit(style: [])

Hopefully that clarifies the issue.

ezekg
  • 924
  • 10
  • 20
1

It looks like it might need to be:

params.require(:book).permit(:title, :description, style: [{:font, :color]})

based on this example from the Rails API Guide

   pets: [{
      name: 'Purplish',
      category: 'dogs'
    }]

Edit, I certainly could be wrong, but following the rules quoted here:

TL;DR: Use this rule of thumb when trying to figure out how to whitelist nested attributes: To Permit a Hash, Pass an Array To Permit an Array, Pass a Hash

creativereason
  • 1,524
  • 1
  • 11
  • 20
  • Is that from the pets example? I think that that is for an _array_ of pets, while I only want one pet with some attributes. – readyornot Apr 17 '15 at 21:11
  • I think you're right about that rule of thumb. Scroll down in that API guide that you linked to and you see this... `params.require(:person).permit(contact: [ :email, :phone ]) # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}}` – readyornot Apr 17 '15 at 21:41
  • When I try this out in a controller spec, the thing that I don't like is that both of the following are permitted... 1) contact: {email: "", phone: ""} <-- this is what I want to permit as it assigns the hash `{email: "", phone: ""}` to the contact attribute. 2) contact: [{email: "1", phone: "1"}, {email: "2", phone: "2"}] <-- only the last email/phone gets passed in, but it assigns the array `[{email: "2", phone: "2"}]` to the contact attribute. I don't like this; I want the contact attribute to only be assigned a hash, not an array. – readyornot Apr 17 '15 at 21:44
  • I wonder if you could get it to do exactly what you want by calling it `params.permit` multiple times or passing in a separate hash like the examples used in the strong_parameters github page? https://github.com/rails/strong_parameters#require-multiple-parameters – creativereason Apr 17 '15 at 21:47
0

I think it should work if you wrap style in curly braces, i.e.:

params.require(:book).permit(:title, :description, { style: [:font, :color] })
Joe Kennedy
  • 9,365
  • 7
  • 41
  • 55
  • Unfortunately, that doesn't work. I get a syntax error... `SyntaxError (.../books_controller.rb:333: syntax error, unexpected ',', expecting => ...le, {style: {:font, :color}}) ...` In my test.log file, the ^ caret is pointing to the comma after `:font` as the source of the problem. – readyornot Apr 17 '15 at 20:50
  • 3
    It's important to remark what @ezekg mentions: `{:font, :color}` is not valid ruby. In general terms, if you want an array of symbols, do `[:font, :color]`. If you would want a key-value hash, stick to the curly braces but do `{ :key => :value }` instead of the comma in the middle (the source of @readyornot syntax error). Or, even better, the modern syntax version `{ key: :value }` which in practice is the same. – Gabriel Osorio Apr 05 '17 at 14:50
  • 3
    @GabrielOsorio: you're totally right. I've fixed my answer. – Joe Kennedy Apr 05 '17 at 14:53