diff options
| -rw-r--r-- | lib/zero/request.rb | 30 | ||||
| -rw-r--r-- | spec/unit/zero/request/method_spec.rb | 43 | 
2 files changed, 72 insertions, 1 deletions
| diff --git a/lib/zero/request.rb b/lib/zero/request.rb index 36ef705..e8f4513 100644 --- a/lib/zero/request.rb +++ b/lib/zero/request.rb @@ -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 diff --git a/spec/unit/zero/request/method_spec.rb b/spec/unit/zero/request/method_spec.rb index 42ea56a..b9352e1 100644 --- a/spec/unit/zero/request/method_spec.rb +++ b/spec/unit/zero/request/method_spec.rb @@ -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 | 
