I tried to use a fetch(… method: ‘PUT’) and I’m getting an InvalidAuthenticityToken error. I’m guessing this has something to do with the csrf token. Has anyone fixed this problem ?
Are you using the jquery_ujs
or the rails_ujs
gem?
In my application I’m using jquery_ujs
and haven’t had any issues with authenticity tokens.
You can query your <meta name="csrf-token">
element for the token and include it in the request’s headers:
fetch(…, {
method: "PUT",
credentials: "same-origin",
headers: {
"X-CSRF-Token": getMetaValue("csrf-token")
},
…
})
function getMetaValue(name) {
const element = document.head.querySelector(`meta[name="${name}"]`)
return element.getAttribute("content")
}
That’s what I ended up doing. I wasn’t sure if that was the best practices.
What was curious though…
document.querySelector(
meta[name="${name}"]).content
#=> worked
however;
$(
meta[name="${name}"]).content
#=> didn’t work work in a debugger in the stimulus controller. If I let the page finish loading, it does work
@scottharvey I’m using the gem, but stimulus is in webpack… so those don’t crossover do they ?
jquery_ujs
has installation instructions for webpack so it should work but I haven’t tried using Webpack.
Just to add my 2 cents to this thread, in a Rails app you can also use Rails-ujs ajax function. It is my understanding that it automatically includes the CSRF token for you.
As an example here is what I have been using in an app:
const data = new FormData();
data.append("myModelName[field]", value);
Rails.ajax({
url: "/my_post_url",
type: "POST",
data
});
I have fixed this in the past using the rails-ujs
module:
import { Controller } from 'stimulus'
import Rails from 'rails-ujs'
export default class extends Controller {
connect() {
fetch('/some/url', {
method: 'PUT',
credentials: 'same-origin',
headers: { 'X-CSRF_Token': Rails.csrfToken() }
})
}
}
Quick update in 2023 for anyone landing on this page.
The Ruby on Rails Guide (for v7) suggests using FetchRequest
from the library @rails/request.js
. This will automatically include the CSRF token in requests.
import { FetchRequest } from '@rails/request.js'
...
async myMethod () {
const request = new FetchRequest('post', 'localhost:3000/posts', {
body: JSON.stringify({ name: 'Request.JS' })
})
const response = await request.perform()
if (response.ok) {
const body = await response.text
}
}
If you’re using another http request library, the token can be included in the request header by querying the meta tag (as others suggested)
document.head.querySelector("meta[name=csrf-token]")?.content