Why doesn't the Rails options wrapper include things hidden from the URI?

parameters wrapper docs :

Wraps a parameter hash in a nested hash. This will allow clients to send POST requests without specifying any root elements.

Helps to have parameter hashes wrapped. The Action Controller review provides the following:

Rails collects all parameters sent along with the request in the params hash, regardless of whether they are sent as part of the request line or message body. [...] The query_parameters hash contains parameters that were sent as part of the query string, and the request_parameters hash contains parameters sent as part of the message body. The path_parameters hash contains parameters that were recognized by routing as part of the path leading to this particular controller and action.

Fun happens when you use RESTful resources and routes. Say you have a model A that has_many Bs; B has a foreign key a_id .

You are POST /as/1/bs with an empty payload (because B has no other fields). Assuming a_id is attr_accessible , we can assume that a_id will be wrapped in object b . Instead, you will see:

 Processing by BsController#create as HTML Parameters: {"b"=>{}, "a_id" => "1"} 

There is no such luck. It turns out that ParamsWrapper uses request_parameters , not params , so not including a_id in the POST payload means t wrap it up. This is rather confusing because you still think that it is included in params , due to URI hangs, and wonder why it was excluded from all things.

Is there any good reason to use request_parameters rather than params here?

I can understand that from the “REST philosophy” point of view, this is a_id if you assume that the payload contains the whole object, but it essentially means that the a_id in the URI is completely ignored, which seems a pity.

tl; dr: ParamsWrapper uses request_parameters as the source of the parameter, so URI-globbed variables are skipped. Is this a Rails bug? Pure REST advocates may say no, but pragmatism suggests yes.

+7
source share
2 answers

As I understand it, the reason why a_id is not included in the hash for 'b', we need the id value to first check if an entry exists in our database. Thus, we can simply reject the other parameters in the request. Due to the fact that he did not include it in the hash "b": he can prevent accidents. Take this scenario: suppose someone updates the form and passes the full hash "b" as an argument to the model object. Now, when we call the model_object.save file, it can save the record in our database instead of updating the old record, which will pose a security risk (it can happen if the object was initialized earlier). Not a script with full proof, but crashes occur during coding, and this can help us prevent such accidents.

0
source

Depending on your specific use case, but if you use strong parameters in your controller, you can do either

 params[:b][:a_id] = params[:a_id] params.require(:b).permit(:a_id) 

or just completely skip the "require" method:

 params.permit(:a_id) 
0
source

All Articles