Skip to content

Commit 5140d0c

Browse files
Allow Ajax.Request to use any HTTP verb without the antiquated _method= URL fallback. (Closes prototypejs#280)
1 parent f63d7f7 commit 5140d0c

File tree

4 files changed

+53
-13
lines changed

4 files changed

+53
-13
lines changed

src/prototype/ajax.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
* `XMLHttpRequest` is used asynchronously or not. Synchronous usage is
4343
* **strongly discouraged** — it halts all script execution for the
4444
* duration of the request _and_ blocks the browser UI.
45+
* * `body` ([[String]]): Specific contents for the request body on a
46+
* method that sends a payload (like `post` or `put`). If it is not
47+
* provided, the contents of the `parameters` option will be used instead.
4548
* * `contentType` ([[String]]; default `application/x-www-form-urlencoded`):
4649
* The `Content-type` header for your request. Change this header if you
4750
* want to send data in another format (like XML).
@@ -57,9 +60,8 @@
5760
* encoded into the URL for a `get` method, or into the request body for the
5861
* other methods. This can be provided either as a URL-encoded string, a
5962
* [[Hash]], or a plain [[Object]].
60-
* * `postBody` ([[String]]): Specific contents for the request body on a
61-
* `post` method. If it is not provided, the contents of the `parameters`
62-
* option will be used instead.
63+
* * `postBody` ([[String]]): An alias for `body` that is provided for
64+
* backward-compatibility. Its use is discouraged.
6365
* * `requestHeaders` ([[Object]]): A set of key-value pairs, with properties
6466
* representing header names.
6567
* * `evalJS` ([[Boolean]] | [[String]]; default `true`): Automatically `eval`s

src/prototype/ajax/request.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,6 @@ Ajax.Request = Class.create(Ajax.Base, {
183183
this.options.parameters :
184184
Object.toQueryString(this.options.parameters);
185185

186-
if (!['get', 'post'].include(this.method)) {
187-
// simulate other verbs over post
188-
params += (params ? '&' : '') + "_method=" + this.method;
189-
this.method = 'post';
190-
}
191-
192186
if (params && this.method === 'get') {
193187
// when GET, append parameters to URL
194188
this.url += (this.url.include('?') ? '&' : '?') + params;
@@ -209,7 +203,12 @@ Ajax.Request = Class.create(Ajax.Base, {
209203
this.transport.onreadystatechange = this.onStateChange.bind(this);
210204
this.setRequestHeaders();
211205

212-
this.body = this.method == 'post' ? (this.options.postBody || params) : null;
206+
if (this.method !== 'get') {
207+
this.body = this.options.body || this.options.postBody || params;
208+
} else {
209+
this.body = null;
210+
}
211+
213212
this.transport.send(this.body);
214213

215214
/* Force Firefox to handle ready state 4 for synchronous requests */
@@ -235,7 +234,7 @@ Ajax.Request = Class.create(Ajax.Base, {
235234
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
236235
};
237236

238-
if (this.method == 'post') {
237+
if (this.method !== 'get') {
239238
// Don't set the `Content-Type` header if the user has explicitly set
240239
// `contentType` to anything falsy.
241240
if (this.options.contentType) {

test/unit/server.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ class UnitTests < Sinatra::Application
5454
})
5555
end
5656

57+
# The '/inspect' endpoint should be available regardless of HTTP method.
58+
def self.handle_inspect(url, &block)
59+
%w{get post put delete patch options head}.each do |verb|
60+
self.send(verb, url, &block)
61+
end
62+
end
5763

5864
def self.get_or_post(url, &block)
5965
get(url, &block)
@@ -108,7 +114,7 @@ def self.get_or_post(url, &block)
108114

109115
# Routes for Ajax tests
110116

111-
get_or_post '/inspect' do
117+
handle_inspect '/inspect' do
112118
response = {
113119
:headers => request_headers(request.env),
114120
:method => request.request_method,

test/unit/tests/ajax.test.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ suite("Ajax", function () {
269269
assert.equal('Hello world!', h2.innerHTML);
270270
});
271271

272-
test('Content-Type set for simulated verbs', function () {
272+
test('Content-Type set for obscure verbs', function () {
273273
new Ajax.Request('/inspect', extendDefault({
274274
method: 'put',
275275
contentType: 'application/bogus',
@@ -282,6 +282,39 @@ suite("Ajax", function () {
282282
}));
283283
});
284284

285+
test('verbs with bodies', function () {
286+
var verbs = $w('post put patch');
287+
verbs.each(function (verb) {
288+
new Ajax.Request('/inspect', extendDefault({
289+
method: verb,
290+
body: 'foo=foo&bar=bar',
291+
onSuccess: function (response) {
292+
var body = response.responseJSON.body;
293+
assert.equal('foo=foo&bar=bar', body, verb + ' should send body');
294+
},
295+
onFailure: function () {
296+
assert(false, verb + ' should send body');
297+
}
298+
}));
299+
});
300+
});
301+
302+
test('verbs without bodies', function () {
303+
var verbs = $w('get head options delete');
304+
305+
verbs.each(function (verb) {
306+
new Ajax.Request('/inspect', extendDefault({
307+
method: verb,
308+
onSuccess: function () {
309+
assert(true, verb + ' method should work');
310+
},
311+
onFailure: function () {
312+
assert(false, verb + ' method should work');
313+
}
314+
}));
315+
});
316+
});
317+
285318
test('onCreate callback', function () {
286319
new Ajax.Request('/fixtures/content.html', extendDefault({
287320
onCreate: function (transport) {

0 commit comments

Comments
 (0)