3

The controller receives JSON object

{
  user: {
    name: "string",
    details: {
      info1: "string",
      info2: []
    }
  }
}

During permission controller knows that can permit some defined fields - as name - and hash field details with all nested attributes - also with arrays. What is the correct solution for this situation?

BAD SOLUTIONS

  1. permit cannot be used, because I must select user permitted fields

  2. tap do |whitelisted| cannot be used, because it doesn't make that fields "permit"

  3. case below cannot be user, because with arrays doesn't work

    details_keys = params[:user][:details].keys

    params.require(:user).permit(:name, details: details_keys)

Wasif Hossain
  • 3,900
  • 1
  • 18
  • 20
ukson
  • 125
  • 4
  • 10
  • I'm not sure you're able to pass an empty array. Have you tried making info2 an empty string instead and see if that works? – gwalshington Feb 01 '17 at 16:49
  • 1
    Are `info1` and `infor2` defined attributes of the nested object? or are they dynamic? – svelandiag Feb 01 '17 at 17:24
  • Hello, can you explain why it is that you write ```2. `tap do |whitelisted|` cannot be used, because it doesn't make that fields "permit"``` Why is it that it doesn't make fields permit ? Thanks – von spotz Feb 23 '20 at 07:30

3 Answers3

5

If you want to permit a key having an array of permitted scalar values, then simply map the key to an empty array:

params.permit(key: [])

The permitted scalar types are String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile, and Rack::Test::UploadedFile

So when an array contains some non-scalar values like a hash, then you have to go further by permitting the nested keys too in the array.

Say, you have the following structure:

{
  key: [
    {
      attr1: 'string',
      attr2: 10
    },
    {
      attr1: 'another string',
      attr2: 100
    }
  ]
}

then the permission goes in this way:

params.permit(key: [:attr1, :attr2])

Now let's assume your case looks like:

{
  user: {
    name: "sting",
    details: {
      info1: "string",
      info2: [1, true, :sym] // assume it contains only permitted scalar values
    }
  }
}

the permission will be:

params.require(:user).permit(:name, details: [:info1, info2: []])

To automate this, lets assume details has 5 attributes with permitted scalar values and 3 more array attributes that also have only scalar values.

First pluck the 5 non-array keys of details:

non_array_keys = params[:user][:details].reject { |_, v| v.class == Array }.keys

Next the 3 array keys inside details:

array_keys = params[:user][:details].select { |_, v| v.class == Array }.keys.map { |k| { k => [] } }

Now the details_keys will be ready by:

details_keys = non_array_keys << array_keys
details_keys.flatten!

Final permission will look like:

params.require(:user).permit(:name, details: details_keys)

If the nested arrays would contain non-scalar values, then I guess you have got enough idea by this point on how to adapt to your changes!

DISCLAIMER: this automation is not appreciated because, instead of doing all these, a simple invocation of params.require(:user).permit! would suffice. But this marks the :user parameters hash and any sub-hash of it as permitted and does not check for permitted scalars, anything is accepted. Extreme care should be taken when using permit!, as it will allow all current and future model attributes to be mass-assigned.

For details, I would strongly suggest to look at the Rails official guide covering Strong Parameters in details.

Wasif Hossain
  • 3,900
  • 1
  • 18
  • 20
0

Adding empty array might work. You can switch off validation for nested attributes?! Are you creating dynamic random input fields which you do not control?

KcUS_unico
  • 513
  • 3
  • 9
  • I have a view with a plenty of various field_tags or checkboxes and I want to send only "changed" fields as JSON field in my object – ukson Feb 02 '17 at 08:43
0

Do you want to pass dynamic fields? If that is the case, the following may work

Configuring strong parameters for dynamic keys

Community
  • 1
  • 1
shivashankar
  • 1,147
  • 1
  • 10
  • 16