20

Using Strong Parameters in my Rails Controller, how can I state that a permitted parameter can be a String or an Array?

My strong params:

class SiteSearchController < ApplicationController
    [...abbreviated for brevity...]

    private
    def search_params
        params.fetch(:search, {}).permit(:strings)
    end
end

I'm wanting to POST string(s) to search as a String or as an Array:

To search for 1 thing:

{
    "strings": "search for this"
}

OR, to search for multiple things:

{
    "strings": [
        "search for this",
        "and for this",
        "and search for this string too"
    ]
}

Update:

Purpose: I'm creating an API where my users can "batch" requests (getting responses via web-hooks), or make a one-off request (getting an immediate response) all on the same endpoint. This question is only 1 small part of my requirement.

The next piece will be doing this same logic, where I'll allow the search to happen on multiple pages, i.e.:

[
    {
        "page": "/section/look-at-this-page",
        "strings": "search for this"
    },
    {
        "page": "/this-page",
        "strings": [
            "search for this",
            "and for this",
            "and search for this string too"
        ]
    }
]

OR on a single page:

{
    "page": "/section/look-at-this-page",
    "strings": "search for this"
}

(which will make me need to have Strong Params allow an Object or an Array to be sent.

This seems like a basic thing, but I'm not seeing anything out there.

I know that I could just make the strings param an array, and then require searching for 1 thing to just have 1 value in the array... but I want to have this parameter be more robust than that.

skplunkerin
  • 2,123
  • 5
  • 28
  • 40

2 Answers2

45

You can just permit the parameter twice - once for an array and once for a scalar value.

def search_params
    params.fetch(:search, {}).permit(:strings, strings: [])
end
tombeynon
  • 2,216
  • 1
  • 20
  • 19
  • 1
    I haven't tested this, but that's clever. Thank you @tombeynon! – skplunkerin Jul 21 '17 at 22:41
  • 7
    It's actually even possible to allow multiple types like so: `params.permit(:attr, { :attr => [] }, { :attr => {} })`. However, as much as I like this behaviour, I couldn't find it anywhere in the documentation... It works, though. – alexb Oct 31 '17 at 09:04
  • 1
    BRILLIANT! Would've never thought of that! :D – Mirko Jul 08 '20 at 11:57
  • 1
    Still works in rails 7, however, in my case, order mattered and I had to put the scalar value before the array. Otherwise, a syntax error was thrown.. – randmin Jun 15 '23 at 07:40
10

You could check if params[:strings] is an array and work from there

def strong_params
  if params[:string].is_a? Array
    params.fetch(:search, {}).permit(strings: [])
  else 
    params.fetch(:search, {}).permit(:strings)
  end
end
Eyeslandic
  • 14,553
  • 13
  • 41
  • 54