4

I am writing a Rails API and attempting to create multiple records at the same time by passing a JSON array into the controller, like this:

[
    {
        "workflow_id": 1,
        "action": "Some Other Action",
        "order": 2,
        "notes": null
    },
    {
        "workflow_id": 1,
        "action": "Some Action",
        "order": 1,
        "notes": null
    }
]

When I view the parameters coming into the controller, this is what I see:

<ActionController::Parameters {"_json"=>[{"workflow_id"=>1, "action"=>"Some Other Action", "order"=>2, "notes"=>nil}, {"workflow_id"=>1, "action"=>"Some Action", "order"=>1, "notes"=>nil}], "controller"=>"workflow_steps", "action"=>"update", "workflow_id"=>"1", "workflow_step"=>{}} permitted: false>

First of all, I'm unfamiliar with _json. Is this a Rails convention for when an array is passed in? I could not find any documentation on it.

Second, When I try this: WorkflowStep.create(params[:_json]) I get the expected ForbiddenAttributesError. But, I cannot figure out how to properly whitelist the json objects in my array. I've tried these:

params.require(:_json).permit(_json: [:workflow_id, :action, :notes, :order])
params.permit(_json: [:workflow_id, :action, :notes, :order])

But I get this error: undefined method permit' for #Array:0x00007ffdeb0f8188`

I am unsure how to proceed. Thank you.

kroe761
  • 3,296
  • 9
  • 52
  • 81

2 Answers2

2

params.require(:_json) returns an array of ActionController::Parameters objects so you can whitelist using the code below:

params.require(:_json).map do |param| 
  param.permit(:workflow_id, :action, :order, :notes).to_h
end
Hamed
  • 1,382
  • 11
  • 20
1

Seems it's a Rails feature, yet I haven't found any documentation for it. While parsing/decoding JSON, if it's not a hash (as JSON supports arrays and even strings) then it places inside _json key on the params object.

You can see the code here:

      DEFAULT_PARSERS = {
        Mime[:json].symbol => -> (raw_post) {
          data = ActiveSupport::JSON.decode(raw_post)
          data.is_a?(Hash) ? data : { _json: data }
        }
      }