Sean
Sean

Reputation: 2577

Rails 5 Params / Strong Params issue

I have a RESTful API (ActionController::API) service that accepts a list of params. The RESTful service takes a JSON body request (with Content-Type of application/json). When I debug the controller/action (right after the action def) and take a peak at the params list, it appears as follows:

<ActionController::Parameters {"given_name"=>"Mark", "subdomain"=>"development", "controller"=>"user", "action"=>"create", "user"=>{"given_name"=>"Mark"}} permitted: false>

EDIT All the request has in it (when it is passed to the controller/action -- using POSTman):

{"given_name":"Mark"}

Notice that the object contains the given_name params twice. Is this normal behavior? I did not pass a "user" object (json object) to the controller/action? What is the permitted flag?

When I try to use (right now I'm just testing RESTful call and assigning any values that the user object will except... no validations have been programmed yet):

user = User.new(params)

I get the error:

#<ActiveModel::ForbiddenAttributesError: ActiveModel::ForbiddenAttributesError>

So, I've looked everywhere for the reasoning behind this (why is there a "user" key in the params list? What is the purpose of the permitted flag? Why am I getting an error when I try to assign params)?

EDIT

After doing some testing, I change the controller name from "user_controller" to "tester_controller" and setup the routes to point to the renamed controller.

It seems the "user" object in the params list above has changed to "tester". So why does the param list contain an "object" with all the passed params with the name of the controller? If that's the case, why is it needed?

Any help would be greatly appreciated.

Upvotes: 2

Views: 7254

Answers (3)

Lyzard Kyng
Lyzard Kyng

Reputation: 1578

By default Rails in API mode wraps JSON request parameters into a hash guessing its name from controller class. That's why changing the controller from User to Tester changes "object" name. You can read details here.

So if you don't need this "object" in your params just remove :json from :format array in config\initializers\wrap_parameters.rb. Or you can use fine-grained control at the controller level as described above.

Upvotes: 3

Sam Coles
Sam Coles

Reputation: 4043

You need to specify which attributes are acceptable for mass-assignment in your controller.

def create
    @user = User.new(params.require(:user).permit(:given_name))
end

This prevents malicious users from making request posts that alter attributes internal to your application, like role in the case of a user object.

As mentioned above, a better explanation can be found in the guide referring to strong parameters.

Upvotes: 1

TeWu
TeWu

Reputation: 6564

You can't pass params to constructor, because params always contain :action and :controller keys. Attributes for new objects should be put in hash under key that identify model you want to create e.g. :user. I suggest you to consult rails guides, especially chapter 7 of "Form Helpers" guide.

If you want to learn more about strong parameters there is a chapter in rails guides for that too :)

Upvotes: 0

Related Questions