0
0
Fork 0

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:
Gibheer 2013-08-14 08:12:39 +02:00
parent 00e0c01703
commit 603dce8628
2 changed files with 72 additions and 1 deletions

View File

@ -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

View File

@ -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