rnmp
rnmp

Reputation: 87

Controller `params` behaving differently on test environment vs. development

I'm using strong parameters for my ShareOptions controller, like so:

def share_option_params
  params.require(:share_option).permit(:public_read, :team_read, :team_write)
end

As you can see, :share_option is required, so when I test PUT with the attributes directly in a JSON body like this: { public_read: true }, my test correctly fails because they're not nested under share_option. Using binding.pry, this is the output of share_option_params:

<ActionController::Parameters {"public_read"=>"true", "format"=>:json, "controller"=>"api/share_options", "action"=>"update", "id"=>"553"} permitted: false>

However, this is not the case with my JS frontend where the same request is successful. There, I'm sending { public_read: true } directly, not nested. In this case, it appears as if share_option is automatically added, here the output of share_options_params:

<ActionController::Parameters {"public_read"=>true, "format"=>:json, "controller"=>"api/share_options", "action"=>"update", "id"=>"332", "share_option"=>{"public_read"=>true}} permitted: false>

At this point, I'm suspecting that Rails is doing something behind the scenes. But it's not clear to me at all as to why this is happening.

Upvotes: 0

Views: 327

Answers (1)

rnmp
rnmp

Reputation: 87

Turns out Rails allows you to omit the root element of your request when making correct JSON requests. In my case, my test wasn't encoding correctly as JSON, so this behavior wasn't occurring.

More information here: https://edgeguides.rubyonrails.org/action_controller_overview.html#json-parameters

[…] if you've turned on config.wrap_parameters in your initializer or called wrap_parameters in your controller, you can safely omit the root element in the JSON parameter. In this case, the parameters will be cloned and wrapped with a key chosen based on your controller's name. So the above JSON request can be written as […]

To avoid this going forward, I plan on wrapping my params in my helper method for tests:

def json_request(params)
  {
    params: params.to_json,
    headers: { 'CONTENT_TYPE' => 'application/json' }
  }
end

Upvotes: 1

Related Questions