-
-
Save anonymous/b309ac31d92a9f07dac8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/Mojolicious/Guides/Routing.pod b/lib/Mojolicious/Guides/Routing.pod | |
index f8b1653..43f5e2c 100644 | |
--- a/lib/Mojolicious/Guides/Routing.pod | |
+++ b/lib/Mojolicious/Guides/Routing.pod | |
@@ -236,6 +236,10 @@ but content will not be sent with the response even if it is present. | |
# HEAD /test -> {controller => 'bar', action => 'test'} | |
$r->get('/test')->to(controller => 'bar', action => 'test'); | |
+You can also use the C<_method> query parameter to override the request method, | |
+this can be very useful when submitting forms with browsers that only support | |
+C<GET> and C<POST>. | |
+ | |
=head2 IRIs | |
IRIs are handled transparently, that means paths are guaranteed to be unescaped | |
diff --git a/lib/Mojolicious/Plugin/TagHelpers.pm b/lib/Mojolicious/Plugin/TagHelpers.pm | |
index bf6ec1b..17a337f 100644 | |
--- a/lib/Mojolicious/Plugin/TagHelpers.pm | |
+++ b/lib/Mojolicious/Plugin/TagHelpers.pm | |
@@ -53,17 +53,14 @@ sub _form_for { | |
push @url, shift if ref $_[0] eq 'HASH'; | |
# POST detection | |
- my @post; | |
+ my (@post, $method); | |
if (my $r = $c->app->routes->lookup($url[0])) { | |
- my %methods = (GET => 1, POST => 1); | |
- do { | |
- my @via = @{$r->via || []}; | |
- %methods = map { $_ => 1 } grep { $methods{$_} } @via if @via; | |
- } while $r = $r->parent; | |
- @post = (method => 'POST') if $methods{POST} && !$methods{GET}; | |
+ @post = (method => 'POST') if ($method = $r->suggested_method) ne 'GET'; | |
} | |
- return _tag('form', action => $c->url_for(@url), @post, @_); | |
+ my $url = $c->url_for(@url); | |
+ $url->query({_method => $method}) if @post && $method ne 'POST'; | |
+ return _tag('form', action => $url, @post, @_); | |
} | |
sub _hidden_field { | |
@@ -366,8 +363,9 @@ Generate C<input> tag of type C<file>. | |
% end | |
Generate portable C<form> tag with L<Mojolicious::Controller/"url_for">. For | |
-routes that allow C<POST> but not C<GET>, a C<method> attribute will be | |
-automatically added. | |
+routes that do not allow C<GET>, a C<method> attribute will be automatically | |
+added. And for methods other than C<GET> and C<POST>, a C<_method> query | |
+parameter will be added as well. | |
<form action="/path/to/login"> | |
<input name="first_name" type="text"> | |
diff --git a/lib/Mojolicious/Routes.pm b/lib/Mojolicious/Routes.pm | |
index bdabbf2..d713913 100644 | |
--- a/lib/Mojolicious/Routes.pm | |
+++ b/lib/Mojolicious/Routes.pm | |
@@ -71,7 +71,7 @@ sub match { | |
else { $path = $req->url->path->to_route } | |
# Method (HEAD will be treated as GET) | |
- my $method = uc $req->method; | |
+ my $method = uc($req->url->query->clone->param('_method') || $req->method); | |
$method = 'GET' if $method eq 'HEAD'; | |
# Check cache | |
diff --git a/lib/Mojolicious/Routes/Route.pm b/lib/Mojolicious/Routes/Route.pm | |
index a98c461..c8bd0f4 100644 | |
--- a/lib/Mojolicious/Routes/Route.pm | |
+++ b/lib/Mojolicious/Routes/Route.pm | |
@@ -128,6 +128,19 @@ sub route { | |
return $route; | |
} | |
+sub suggested_method { | |
+ my $self = shift; | |
+ | |
+ my %methods; | |
+ for my $route (@{$self->_chain}) { | |
+ next unless my @via = @{$route->via || []}; | |
+ %methods = map { $_ => 1 } grep { keys %methods ? $methods{$_} : 1 } @via; | |
+ } | |
+ return 'POST' if $methods{POST} && !$methods{GET}; | |
+ return 'GET' if $methods{GET}; | |
+ return (sort keys %methods)[0] || 'GET'; | |
+} | |
+ | |
sub to { | |
my $self = shift; | |
@@ -492,6 +505,12 @@ The L<Mojolicious::Routes> object this route is a descendant of. | |
Low-level generator for routes matching all HTTP request methods, returns a | |
L<Mojolicious::Routes::Route> object. | |
+=head2 suggested_method | |
+ | |
+ my $method = $r->suggested_method; | |
+ | |
+Suggested HTTP method for this route, C<GET> and C<POST> are preferred. | |
+ | |
=head2 to | |
my $defaults = $r->to; | |
diff --git a/t/mojolicious/tag_helper_lite_app.t b/t/mojolicious/tag_helper_lite_app.t | |
index 68a6bfe..fae4ddf 100644 | |
--- a/t/mojolicious/tag_helper_lite_app.t | |
+++ b/t/mojolicious/tag_helper_lite_app.t | |
@@ -313,7 +313,7 @@ EOF | |
# Empty selection | |
$t->put_ok('/selection')->status_is(200) | |
- ->content_is("<form action=\"/selection\">\n " | |
+ ->content_is("<form action=\"/selection?_method=PUT\" method=\"POST\">\n " | |
. '<select name="a">' | |
. '<option value="b">b</option>' | |
. '<optgroup label="c">' | |
@@ -342,7 +342,7 @@ $t->put_ok('/selection')->status_is(200) | |
# Selection with values | |
$t->put_ok('/selection?a=e&foo=bar&bar=baz&yada=b')->status_is(200) | |
- ->content_is("<form action=\"/selection\">\n " | |
+ ->content_is("<form action=\"/selection?_method=PUT\" method=\"POST\">\n " | |
. '<select name="a">' | |
. '<option value="b">b</option>' | |
. '<optgroup label="c">' | |
@@ -372,7 +372,7 @@ $t->put_ok('/selection?a=e&foo=bar&bar=baz&yada=b')->status_is(200) | |
# Selection with multiple values | |
$t->put_ok('/selection?foo=bar&a=e&foo=baz&bar=d&yada=a&yada=b') | |
->status_is(200) | |
- ->content_is("<form action=\"/selection\">\n " | |
+ ->content_is("<form action=\"/selection?_method=PUT\" method=\"POST\">\n " | |
. '<select name="a">' | |
. '<option value="b">b</option>' | |
. '<optgroup label="c">' | |
@@ -401,7 +401,7 @@ $t->put_ok('/selection?foo=bar&a=e&foo=baz&bar=d&yada=a&yada=b') | |
# Selection with multiple values preselected | |
$t->put_ok('/selection?preselect=1')->status_is(200) | |
- ->content_is("<form action=\"/selection\">\n " | |
+ ->content_is("<form action=\"/selection?_method=PUT\" method=\"POST\">\n " | |
. '<select name="a">' | |
. '<option selected value="b">b</option>' | |
. '<optgroup label="c">' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment