add request method override for browsers
Browsers are not able to send put, delete or any other request from a plain html form. This limits the possibilities with APIs so an override was introduced in many frameworks in the form, that `_method` could be defined in a post payload. With this, zero also supports `_method` in the post payload to make it possible to use all functions of the API with javascript through plain html.
This commit is contained in:
parent
00e0c01703
commit
603dce8628
|
@ -68,7 +68,8 @@ module Zero
|
|||
# get the method of the request
|
||||
# @return [Symbol] the symbol representation of the method
|
||||
def method
|
||||
@method ||= @env[CONST_REQUEST_METHOD].downcase.to_sym
|
||||
return @method if @method
|
||||
@method = extract_method
|
||||
end
|
||||
# is the method 'GET'?
|
||||
# @return [Boolean] true if this is a get request
|
||||
|
@ -103,5 +104,32 @@ module Zero
|
|||
# constant for the request method key
|
||||
# @api private
|
||||
CONST_REQUEST_METHOD = 'REQUEST_METHOD'
|
||||
# regex to match for valid http methods
|
||||
CONST_VALID_METHODS = /\A(get|post|put|delete|head|link|unlink|patch)\Z/
|
||||
# constant for post
|
||||
CONST_POST = 'post'
|
||||
# constant for the method keyword
|
||||
CONST_METHOD = '_method'
|
||||
|
||||
# this function tries to figure out what method the request used
|
||||
#
|
||||
# The problem with extracting the request method is, that every client out
|
||||
# there can speak all methods (get, post, put, whatever) but not browsers.
|
||||
# When sending a form, they can only send get or post forms, but not put
|
||||
# or delete, which makes them a pain to use. So instead an override was
|
||||
# introduced in rails and other frameworks to support `_method` in the post
|
||||
# payload.
|
||||
# So this function does essentially the same, so please do not remove it
|
||||
# until browsers learned how to do it.
|
||||
# @return [Symbol] the extracted method
|
||||
def extract_method
|
||||
method = @env[CONST_REQUEST_METHOD].downcase
|
||||
return method.to_sym unless method == CONST_POST
|
||||
if params.payload.has_key?(CONST_METHOD)
|
||||
method = params.payload[CONST_METHOD].downcase
|
||||
return method.to_sym if CONST_VALID_METHODS.match(method)
|
||||
end
|
||||
CONST_POST.to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,4 +5,47 @@ describe Zero::Request, '#method' do
|
|||
let(:env) { EnvGenerator.get('/foo') }
|
||||
|
||||
its(:method) { should == :get }
|
||||
|
||||
context 'with post requests' do
|
||||
context 'and _method defined' do
|
||||
let(:env) do
|
||||
EnvGenerator.post('/foo', {
|
||||
:input => '_method=put',
|
||||
'CONTENT_TYPE' => 'multipart/form-data'
|
||||
})
|
||||
end
|
||||
it 'uses _method from the payload to change the method' do
|
||||
expect(subject.method).to be(:put)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and _method not defined' do
|
||||
let(:env) do
|
||||
EnvGenerator.post('/foo', {
|
||||
:input => 'foo=bar',
|
||||
'CONTENT_TYPE' => 'multipart/form-data'
|
||||
})
|
||||
end
|
||||
its(:method) { should == :post }
|
||||
end
|
||||
|
||||
context 'and _method has wrong content' do
|
||||
let(:env) do
|
||||
EnvGenerator.post('/foo', {
|
||||
:input => '_method=foobar',
|
||||
'CONTENT_TYPE' => 'multipart/form-data'
|
||||
})
|
||||
end
|
||||
its(:method) { should == :post }
|
||||
end
|
||||
|
||||
context 'and no payload' do
|
||||
let(:env) do
|
||||
EnvGenerator.post('/foo', {
|
||||
'CONTENT_TYPE' => 'multipart/form-data'
|
||||
})
|
||||
end
|
||||
its(:method) { should == :post }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue