Skip to content

Commit

Permalink
Add Type Safety Guards to turbo/fetch_requests
Browse files Browse the repository at this point in the history
Without this change, GET `<form>` submissions without a Fetch Options `{
body: }` raise the following:

```
Uncaught TypeError: s.body is null
    <anonymous> fetch_requests.js:10
    w turbo.es2017-esm.js:351
    requestStarted turbo.es2017-esm.js:770
    perform turbo.es2017-esm.js:520
    start turbo.es2017-esm.js:744
    formSubmitted turbo.es2017-esm.js:3369
```

Through the exercise of attempting to [port the `turbo/fetch_requests`
module to
TypeScript](#392 (comment)),
we've identified some potential edge cases in the algorithm that
determines a request's HTTP method.

Even if the migration to TypeScript doesn't come to fruition for some
time, those edge cases should be addressed sooner rather than later.

This commit adds more "type safety" motivated conditionals and guards to
make sure that values are present before overriding them.
  • Loading branch information
seanpdoyle committed Nov 19, 2022
1 parent 2a80b2c commit 6d87887
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 8 deletions.
36 changes: 33 additions & 3 deletions app/assets/javascripts/turbo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4025,12 +4025,13 @@ function encodeMethodIntoRequestBody(event) {
if (event.target instanceof HTMLFormElement) {
const {target: form, detail: {fetchOptions: fetchOptions}} = event;
form.addEventListener("turbo:submit-start", (({detail: {formSubmission: {submitter: submitter}}}) => {
const method = submitter && submitter.formMethod || fetchOptions.body && fetchOptions.body.get("_method") || form.getAttribute("method");
const body = isBodyInit(fetchOptions.body) ? fetchOptions.body : new URLSearchParams;
const method = determineFetchMethod(submitter, body, form);
if (!/get/i.test(method)) {
if (/post/i.test(method)) {
fetchOptions.body.delete("_method");
body.delete("_method");
} else {
fetchOptions.body.set("_method", method);
body.set("_method", method);
}
fetchOptions.method = "post";
}
Expand All @@ -4040,6 +4041,35 @@ function encodeMethodIntoRequestBody(event) {
}
}

function determineFetchMethod(submitter, body, form) {
const formMethod = determineFormMethod(submitter);
const overrideMethod = body.get("_method");
const method = form.getAttribute("method") || "get";
if (typeof formMethod == "string") {
return formMethod;
} else if (typeof overrideMethod == "string") {
return overrideMethod;
} else {
return method;
}
}

function determineFormMethod(submitter) {
if (submitter instanceof HTMLButtonElement || submitter instanceof HTMLInputElement) {
if (submitter.hasAttribute("formmethod")) {
return submitter.formMethod;
} else {
return null;
}
} else {
return null;
}
}

function isBodyInit(body) {
return body instanceof FormData || body instanceof URLSearchParams;
}

addEventListener("turbo:before-fetch-request", encodeMethodIntoRequestBody);

var adapters = {
Expand Down

0 comments on commit 6d87887

Please sign in to comment.