Suppose you have a url
localhost:3000?a=1
and in the request, you also have a post parameter
a=2
What would
params[:a]
be in this case? does it depend on the HTTP verb?
If it does depend on the HTTP verb,
what if your form looks like
<form method='post' action='/?a=2'>
<input type='hidden' name='a' value='3'/>
</form>
what would params[:a]
be in this case?
UPDATE
So I just did a small experiment and used Chrome Debugger to append ?authenticity_token=abc
the action url. I looked at the server log and I saw that parameters has authenticity_token => 'abc'
. I also believe that the method is POST
in this case.
Let me know what you guys came up with.
When I tried this in a sample code, what I was able to see was that query parameters(GET) are given precedence than the POST body. So, I went digging into the code of Rack
which handles the HTTP requests in Rails. Here is the code from request.rb
# Returns the data recieved in the query string.
def GET
....
end
# Returns the data recieved in the request body.
#
# This method support both application/x-www-form-urlencoded and
# multipart/form-data.
def POST
....
end
# The union of GET and POST data.
def params
@params ||= self.GET.merge(self.POST)
rescue EOFError
self.GET
end
Here, the method
So, according to the code for params
, the GET parameters should get overridden by POST parameters in case of identical keys. (self.GET.merge(self.POST)
). But, this is contrary to what I got when I tried it practically.
So, the only chance is that this code is being overridden by Rails. When I thought about it, it made perfect sense as the params
hash from the Rails will always contain "controller"
and "action"
keys, which will be absent in case of Rack. So, I looked at the code of Rails also, and found that params
method was indeed being overridden. Take a look at request.rb and parameters.rb in Rails source code. In parameters.rb, we have:
# Returns both GET and POST \parameters in a single hash.
def parameters
@env["action_dispatch.request.parameters"] ||= begin
params = request_parameters.merge(query_parameters)
params.merge!(path_parameters)
encode_params(params).with_indifferent_access
end
end
alias :params :parameters
and in request.rb:
# Override Rack's GET method to support indifferent access
def GET
@env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {})
end
alias :query_parameters :GET
# Override Rack's POST method to support indifferent access
def POST
@env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {})
end
alias :request_parameters :POST
So, here
params
(It was overridden here)Note that GET method and POST method were also overridden, mainly to convert the hash returned to an object of HashWithIndifferentAccess.
So, looking at the code here (params = request_parameters.merge(query_parameters)
), it becomes evident that POST parameters are overridden by GET parameters in case of identical keys, in Rails. Or in other words, GET parameters are given precedence over POST parameters.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With