diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index d4d2225add..f0a3ee9ade 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -83,8 +83,6 @@ proper prerequisites installed. These include: * Ruby * SQLite3 -* Node.js -* Yarn #### Installing Ruby @@ -121,31 +119,6 @@ $ sqlite3 --version The program should report its version. -#### Installing Node.js and Yarn - -Finally, you'll need Node.js and Yarn installed to manage your application's JavaScript. - -Find the installation instructions at the [Node.js website](https://nodejs.org/en/download/) and -verify it's installed correctly with the following command: - -```bash -$ node --version -``` - -The version of your Node.js runtime should be printed out. Make sure it's greater -than 8.16.0. - -To install Yarn, follow the installation -instructions at the [Yarn website](https://classic.yarnpkg.com/en/docs/install). - -Running this command should print out Yarn version: - -```bash -$ yarn --version -``` - -If it says something like "1.22.0", Yarn has been installed correctly. - #### Installing Rails To install Rails, use the `gem install` command provided by RubyGems: diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index ee975c2e2c..469dcfb949 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -3,561 +3,274 @@ Working with JavaScript in Rails ================================ -This guide covers the built-in Ajax/JavaScript functionality of Rails (and -more); it will enable you to create rich and dynamic Ajax applications with -ease! +This guide covers the options for integrating JavaScript functionality into your Rails application, +including the options you have for using external JavaScript packages and how to use Turbo with +Rails. After reading this guide, you will know: -* The basics of Ajax. -* Unobtrusive JavaScript. -* How Rails' built-in helpers assist you. -* How to handle Ajax on the server side. -* The Turbolinks gem. -* How to include your Cross-Site Request Forgery token in request headers +* How to use Rails without the need for a Node.js, Yarn, or a JavaScript bundler. +* How to create a new Rails application using import maps, esbuild, rollup, or webpack to bundle +your JavaScript. +* What Turbo is, and how to use it. +* How to use the Turbo HTML helpers provided by Rails. -------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -An Introduction to Ajax ------------------------- +Import maps +----------- -In order to understand Ajax, you must first understand what a web browser does -normally. +[Import maps](https://github.com/rails/importmap-rails) let you import JavaScript modules using +logical names that map to versioned files directly from the browser. Import maps are the default +from Rails 7, allowing anyone to build modern JavaScript applications using most NPM packages +without the need for transpiling or bundling. -When you type `http://localhost:3000` into your browser's address bar and hit -'Go', the browser (your 'client') makes a request to the server. It parses the -response, then fetches all associated assets, like JavaScript files, -stylesheets and images. It then assembles the page. If you click a link, it -does the same process: fetch the page, fetch the assets, put it all together, -show you the results. This is called the 'request response cycle'. +Applications using import maps do not need [Node.js](https://nodejs.org/en/) or +[Yarn](https://yarnpkg.com/) to function. If you plan to use Rails with `importmap-rails` to +manage your JavaScript dependencies, there is no need to install Node.js or Yarn. -JavaScript can also make requests to the server, and parse the response. It -also has the ability to update information on the page. Combining these two -powers, a JavaScript writer can make a web page that can update just parts of -itself, without needing to get the full page data from the server. This is a -powerful technique that we call Ajax. +When using import maps, no separate build process is required, just start your server with +`bin/rails server` and you are good to go. -As an example, here's some JavaScript code that makes an Ajax request: +### Adding NPM Packages with importmap-rails -```js -fetch("/test") - .then((data) => data.text()) - .then((html) => { - const results = document.querySelector("#results"); - results.insertAdjacentHTML("beforeend", html); - }); +To add new packages to your import map-powered application, run the `bin/importmap pin` command +from your terminal: + +```bash +$ bin/importmap pin react react-dom ``` -This code fetches data from "/test", and then appends the result to the element -with an id of `results`. - -Rails provides quite a bit of built-in support for building web pages with this -technique. You rarely have to write this code yourself. The rest of this guide -will show you how Rails can help you write websites in this way, but it's -all built on top of this fairly simple technique. - -Unobtrusive JavaScript ----------------------- - -Rails uses a technique called "Unobtrusive JavaScript" to handle attaching -JavaScript to the DOM. This is generally considered to be a best-practice -within the frontend community, but you may occasionally read tutorials that -demonstrate other ways. - -Here's the simplest way to write JavaScript. You may see it referred to as -'inline JavaScript': - -```html -Paint it red +Then, import the package into `application.js` as usual: +```javascript +import React from "react" +import ReactDOM from "react-dom" ``` -When clicked, the link background will become red. Here's the problem: what -happens when we have lots of JavaScript we want to execute on a click? +Adding NPM Packages with JavaScript Bundlers +-------- -```html -Paint it green +Import maps are the default for new Rails applications, but if you prefer traditional JavaScript +bundling, you can create new Rails applications with your choice of +[esbuild](https://esbuild.github.io/), [webpack](https://webpack.js.org/), or +[rollup.js](https://rollupjs.org/guide/en/). + +To use a bundler instead of import maps in a new Rails application, pass the `—javascript` or `-j` +option to `rails new`: +``` +$ rails new my_new_app --javascript=webpack +OR +$ rails new my_new_app -j webpack ``` -Awkward, right? We could pull the function definition out of the click handler, -and turn it into a function: +These bundling options each come with a simple configuration and integration with the asset +pipeline via the [jsbundling-rails](https://github.com/rails/jsbundling-rails) gem. -```js -window.paintIt = function(event, backgroundColor, textColor) { - event.preventDefault(); - event.target.style.backgroundColor = backgroundColor; - if (textColor) { - event.target.style.color = textColor; - } -} +When using a bundling option, use `bin/dev` to start the Rails server and build JavaScript for +development. + +### Installing Node.js and Yarn + +If you are using a JavaScript bundler in your Rails application, Node.js and Yarn must be +installed. + +Find the installation instructions at the [Node.js website](https://nodejs.org/en/download/) and +verify it’s installed correctly with the following command: + +```bash +$ node --version ``` -And then on our page: +The version of your Node.js runtime should be printed out. Make sure it’s greater than `8.16.0`. -```html -Paint it red +To install Yarn, follow the installation instructions at the +[Yarn website](https://classic.yarnpkg.com/en/docs/install). Running this command should print out +the Yarn version: + +```bash +$ yarn --version ``` -That's a little bit better, but what about multiple links that have the same -effect? +If it says something like `1.22.0`, Yarn has been installed correctly. -```html -Paint it red -Paint it green -Paint it blue -``` +Choosing Between Import Maps and a JavaScript Bundler +----------------------------------------------------- -Not very DRY, eh? We can fix this by using events instead. We'll add a `data-*` -attribute to our link, and then bind a handler to the click event of every link -that has that attribute: +When you create a new Rails application, you will need to choose between import maps and a +JavaScript bundling solution. Every application has different requirements, and you should +consider your requirements carefully before choosing a JavaScript option, as migrating from one +option to another may be time-consuming for large, complex applications. -```js -function paintIt(element, backgroundColor, textColor) { - element.style.backgroundColor = backgroundColor; - if (textColor) { - element.style.color = textColor; - } -} +Import maps are the default option because the Rails team believes in import maps' potential for +reducing complexity, improving developer experience, and delivering performance gains. -window.addEventListener("load", () => { - const links = document.querySelectorAll( - "a[data-background-color]" - ); - links.forEach((element) => { - element.addEventListener("click", (event) => { - event.preventDefault(); +For many applications, especially those that rely primarily on the [Hotwire](https://hotwired.dev/) +stack for their JavaScript needs, import maps will be the right option for the long term. You +can read more about the reasoning behind making import maps the default in Rails 7 +[here](https://world.hey.com/dhh/rails-7-will-have-three-great-answers-to-javascript-in-2021-8d68191b). - const {backgroundColor, textColor} = element.dataset; - paintIt(element, backgroundColor, textColor); - }); - }); -}); -``` -```html -Paint it red -Paint it green -Paint it blue -``` +Other applications may still need a traditional JavaScript bundler. Requirements that indicate +that you should choose a traditional bundler include: -We call this 'unobtrusive' JavaScript because we're no longer mixing our -JavaScript into our HTML. We've properly separated our concerns, making future -change easy. We can easily add behavior to any link by adding the data -attribute. We can run all of our JavaScript through a minimizer and -concatenator. We can serve our entire JavaScript bundle on every page, which -means that it'll get downloaded on the first page load and then be cached on -every page after that. Lots of little benefits really add up. +* If your code requires a transpilation step, such as JSX or TypeScript. +* If you need to use JavaScript libraries that include CSS or otherwise rely on +[Webpack loaders](https://webpack.js.org/loaders/). +* If you are absolutely sure that you need +[tree-shaking](https://webpack.js.org/guides/tree-shaking/). +* If you will install Bootstrap, Bulma, PostCSS, or Dart CSS through the +[cssbundling-rails gem](https://github.com/rails/cssbundling-rails). All options provided by this +gem except Tailwind will automatically install `esbuild` for you if you do not specify a different +option in `rails new`. -Built-in Helpers ----------------- +Turbo +----- -### Remote Elements +Whether you choose import maps or a traditional bundler, Rails ships with +[Turbo](https://turbo.hotwired.dev/) to speed up your application while dramatically reducing the +amount of JavaScript that you will need to write. -Rails provides a bunch of view helper methods written in Ruby to assist you -in generating HTML. Sometimes, you want to add a little Ajax to those elements, -and Rails has got your back in those cases. +Turbo lets your server deliver HTML directly as an alternative to the prevailing front-end +frameworks that reduce the server-side of your Rails application to little more than a JSON API. -Because of Unobtrusive JavaScript, the Rails "Ajax helpers" are actually in two -parts: the JavaScript half and the Ruby half. +### Turbo Drive -Unless you have disabled the Asset Pipeline, -[rails-ujs](https://github.com/rails/rails/tree/main/actionview/app/assets/javascripts) -provides the JavaScript half, and the regular Ruby view helpers add appropriate -tags to your DOM. +[Turbo Drive](https://turbo.hotwired.dev/handbook/drive) speeds up page loads by avoiding full-page +teardowns and rebuilds on every navigation request. Turbo Drive is an improvement on and +replacement for Turbolinks. -You can read below about the different events that are fired dealing with -remote elements inside your application. +### Turbo Frames -#### form_with +[Turbo Frames](https://turbo.hotwired.dev/handbook/frames) allow predefined parts of a page to be +updated on request, without impacting the rest of the page’s content. -[`form_with`](https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with) -is a helper that assists with writing forms. To use Ajax for your form you can -pass the `:local` option to `form_with`. +You can use Turbo Frames to build in-place editing without any custom JavaScript, lazy load +content, and create server-rendered, tabbed interfaces with ease. + +Rails provides HTML helpers to simplify the use of Turbo Frames through the +[turbo-rails](https://github.com/hotwired/turbo-rails) gem. + +Using this gem, you can add a Turbo Frame to your application with the `turbo_frame_tag` helper +like this: ```erb -<%= form_with(model: @article, id: "new-article", local: false) do |form| %> - ... +<%= turbo_frame_tag dom_id(post) do %> +
+ <%= link_to post.title, post_path(path) %> +
<% end %> ``` -This will generate the following HTML: +### Turbo Streams -```html -
- ... -
+[Turbo Streams](https://turbo.hotwired.dev/handbook/streams) deliver page changes as fragments of +HTML wrapped in self-executing `` elements. Turbo Streams allow you to broadcast +changes made by other users over WebSockets and update pieces of a page after a form submission +without requiring a full page load. + +Rails provides HTML and server-side helpers to simplify the use of Turbo Streams through the +[turbo-rails](https://github.com/hotwired/turbo-rails) gem. + +Using this gem, you can render Turbo Streams from a controller action: + +```ruby +def create + @post = Post.new(post_params) + + respond_to do |format| + if @post.save + format.turbo_stream + else + format.html { render :new, status: :unprocessable_entity } + end + end +end ``` -Note the `data-remote="true"`. Now, the form will be submitted by Ajax rather -than by the browser's normal submit mechanism. +Rails will automatically look for a `.turbo_stream.erb` view file and render that view when found. -You probably don't want to just sit there with a filled out `
`, though. -You probably want to do something upon a successful submission. To do that, -bind to the `ajax:success` event. On failure, use `ajax:error`. Check it out: +Turbo Stream responses can also be rendered inline in the controller action: -```js -window.addEventListener("load", () => { - const element = document.querySelector("#new-article"); - element.addEventListener("ajax:success", (event) => { - const [_data, _status, xhr] = event.detail; - element.insertAdjacentHTML("beforeend", xhr.responseText); - }); - element.addEventListener("ajax:error", () => { - element.insertAdjacentHTML("beforeend", "

ERROR

"); - }); -}); +```ruby +def create + @post = Post.new(post_params) + + respond_to do |format| + if @post.save + format.turbo_stream { render turbo_stream: turbo_stream.prepend('posts', partial: 'post') } + else + format.html { render :new, status: :unprocessable_entity } + end + end +end ``` -Obviously, you'll want to be a bit more sophisticated than that, but it's a -start. +Finally, Turbo Streams can be initiated from a model or a background job using built-in helpers. +These broadcasts can be used to update content via a WebSocket connection to all users, keeping +page content fresh and bringing your application to life. -#### link_to +To broadcast a Turbo Stream from a model combine a model callback like this: -[`link_to`](https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to) -is a helper that assists with generating links. It has a `:remote` option you -can use like this: +```ruby +class Post < ApplicationRecord + after_create_commit { broadcast_append_to('posts') } +end +``` + +With a WebSocket connection set up on the page that should receive the updates like this: ```erb -<%= link_to "an article", @article, remote: true %> +<%= turbo_stream_from "posts" %> ``` -which generates +Replacements for Rails/UJS Functionality +---------------------------------------- -```html -an article -``` +Rails 6 shipped with a tool called UJS that allows developers to override the method of `` tags +to perform non-GET requests after a hyperlink click and to add confirmation dialogs before +executing an action. This was the default before Rails 7, but it is now recommended to use Turbo +instead. -You can bind to the same Ajax events as `form_with`. Here's an example. Let's -assume that we have a list of articles that can be deleted with just one -click. We would generate some HTML like this: +### Method + +Clicking links always results in an HTTP GET request. If your application is +[RESTful](https://en.wikipedia.org/wiki/Representational_State_Transfer), some links are in fact +actions that change data on the server, and should be performed with non-GET requests. This +attribute allows marking up such links with an explicit method such as "post", "put", or "delete". + +Turbo will scan `` tags in your application for the `turbo-method` data attribute and use the +specified method when present, overriding the default GET action. + +For example: ```erb -<%= link_to "Delete article", @article, remote: true, method: :delete %> -``` - -and write some JavaScript like this: - -```js -window.addEventListener("load", () => { - const links = document.querySelectorAll("a[data-remote]"); - links.forEach((element) => { - element.addEventListener("ajax:success", () => { - alert("The article was deleted."); - }); - }); -}); -``` - -#### button_to - -[`button_to`](https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to) is a helper that helps you create buttons. It has a `:remote` option that you can call like this: - -```erb -<%= button_to "An article", @article, remote: true %> -``` - -this generates - -```html - - - -``` - -Since it's just a `
`, all the information on `form_with` also applies. - -### Customize Remote Elements - -It is possible to customize the behavior of elements with a `data-remote` -attribute without writing a line of JavaScript. You can specify extra `data-` -attributes to accomplish this. - -#### `data-method` - -Activating hyperlinks always results in an HTTP GET request. However, if your -application is [RESTful](https://en.wikipedia.org/wiki/Representational_State_Transfer), -some links are in fact actions that change data on the server, and must be -performed with non-GET requests. This attribute allows marking up such links -with an explicit method such as "post", "put" or "delete". - -The way it works is that, when the link is activated, it constructs a hidden form -in the document with the "action" attribute corresponding to "href" value of the -link, and the method corresponding to `data-method` value, and submits that form. - -NOTE: Because submitting forms with HTTP methods other than GET and POST isn't -widely supported across browsers, all other HTTP methods are actually sent over -POST with the intended method indicated in the `_method` parameter. Rails -automatically detects and compensates for this. - -#### `data-url` and `data-params` - -Certain elements of your page aren't actually referring to any URL, but you may want -them to trigger Ajax calls. Specifying the `data-url` attribute along with -the `data-remote` one will trigger an Ajax call to the given URL. You can also -specify extra parameters through the `data-params` attribute. - -This can be useful to trigger an action on check-boxes for instance: - -```html - -``` - -#### `data-type` - -It is also possible to define the Ajax `dataType` explicitly while performing -requests for `data-remote` elements, by way of the `data-type` attribute. - -### Confirmations - -You can ask for an extra confirmation of the user by adding a `data-confirm` -attribute on links and forms. The user will be presented with a JavaScript `confirm()` -dialog containing the attribute's text. If the user chooses to cancel, the action -doesn't take place. - -Adding this attribute on links will trigger the dialog on click, and adding it -on forms will trigger it on submit. For example: - -```erb -<%= link_to "Dangerous zone", dangerous_zone_path, - data: { confirm: 'Are you sure?' } %> +<%= link_to "Delete post", post_path(post), data: { turbo_method: "delete" } %> ``` This generates: ```html -Dangerous zone +Delete post ``` -The attribute is also allowed on form submit buttons. This allows you to customize -the warning message depending on the button which was activated. In this case, -you should **not** have `data-confirm` on the form itself. +An alternative to changing the method of a link with `data-turbo-method` is to use Rails +`button_to` helper. For accessibility reasons, actual buttons and forms are preferable for any +non-GET action. +### Confirmations -### Automatic disabling +You can ask for an extra confirmation of the user by adding a `data-turbo-confirm` attribute on +links and forms. The user will be presented with a JavaScript `confirm()` dialog containing the +attribute’s text. If the user chooses to cancel, the action doesn't take place. -It is also possible to automatically disable an input while the form is submitting -by using the `data-disable-with` attribute. This is to prevent accidental -double-clicks from the user, which could result in duplicate HTTP requests that -the backend may not detect as such. The value of the attribute is the text that will -become the new value of the button in its disabled state. - -This also works for links with `data-method` attribute. - -For example: +Adding this attribute on links will trigger the dialog on click, and adding it on forms will +trigger it on submit. For example: ```erb -<%= form_with(model: Article.new) do |form| %> - <%= form.submit data: { disable_with: "Saving..." } %> -<% end %> +<%= link_to "Delete post", post_path(post), data: { turbo_method: "delete", turbo_confirm: "Are you sure?" } %> ``` -This generates a form with: +This generates: ```html - +Delete post ``` - -### Rails-ujs event handlers - -Rails 5.1 introduced rails-ujs and dropped jQuery as a dependency. -As a result the Unobtrusive JavaScript (UJS) driver has been rewritten to operate without jQuery. -These introductions cause small changes to `custom events` fired during the request: - -NOTE: Signature of calls to UJS's event handlers has changed. -Unlike the version with jQuery, all custom events return only one parameter: `event`. -In this parameter, there is an additional attribute `detail` which contains an array of extra parameters. -For information about the previously used `jquery-ujs` in Rails 5 and earlier, read the [`jquery-ujs` wiki](https://github.com/rails/jquery-ujs/wiki/ajax). - -| Event name | Extra parameters (event.detail) | Fired | -|---------------------|---------------------------------|-------------------------------------------------------------| -| `ajax:before` | | Before the whole ajax business. | -| `ajax:beforeSend` | [xhr, options] | Before the request is sent. | -| `ajax:send` | [xhr] | When the request is sent. | -| `ajax:stopped` | | When the request is stopped. | -| `ajax:success` | [response, status, xhr] | After completion, if the response was a success. | -| `ajax:error` | [response, status, xhr] | After completion, if the response was an error. | -| `ajax:complete` | [xhr, status] | After the request has been completed, no matter the outcome.| - -Example usage: - -```js -document.body.addEventListener("ajax:success", (event) => { - const [data, status, xhr] = event.detail; -}); -``` - -### Stoppable events - -You can stop execution of the Ajax request by running `event.preventDefault()` -from the handlers methods `ajax:before` or `ajax:beforeSend`. -The `ajax:before` event can manipulate form data before serialization and the -`ajax:beforeSend` event is useful for adding custom request headers. - -If you stop the `ajax:aborted:file` event, the default behavior of allowing the -browser to submit the form via normal means (i.e. non-Ajax submission) will be -canceled, and the form will not be submitted at all. This is useful for -implementing your own Ajax file upload workaround. - -Note, you should use `return false` to prevent an event for `jquery-ujs` and -`event.preventDefault()` for `rails-ujs`. - -Server-Side Concerns --------------------- - -Ajax isn't just client-side, you also need to do some work on the server -side to support it. Often, people like their Ajax requests to return JSON -rather than HTML. Let's discuss what it takes to make that happen. - -### A Simple Example - -Imagine you have a series of users that you would like to display and provide a -form on that same page to create a new user. The index action of your -controller looks like this: - -```ruby -class UsersController < ApplicationController - def index - @users = User.all - @user = User.new - end - # ... -``` - -The index view (`app/views/users/index.html.erb`) contains: - -```erb -Users - - - -
- -<%= form_with model: @user, local: false do |form| %> - <%= form.label :name %>
- <%= form.text_field :name %> - <%= form.submit %> -<% end %> -``` - -The `app/views/users/_user.html.erb` partial contains the following: - -```erb -
  • <%= user.name %>
  • -``` - -The top portion of the index page displays the users. The bottom portion -provides a form to create a new user. - -The bottom form will call the `create` action on the `UsersController`. Because -the form's remote option is set to true, the request will be posted to the -`UsersController` as an Ajax request, looking for JavaScript. In order to -serve that request, the `create` action of your controller would look like -this: - -```ruby - # app/controllers/users_controller.rb - # ...... - def create - @user = User.new(params[:user]) - - respond_to do |format| - if @user.save - format.html { redirect_to @user, notice: 'User was successfully created.' } - format.js - format.json { render json: @user, status: :created, location: @user } - else - format.html { render action: "new" } - format.json { render json: @user.errors, status: :unprocessable_entity } - end - end - end -``` - -Notice the `format.js` in the `respond_to` block: that allows the controller to -respond to your Ajax request. You then have a corresponding -`app/views/users/create.js.erb` view file that generates the actual JavaScript -code that will be sent and executed on the client side. - -```js -var users = document.querySelector("#users"); -users.insertAdjacentHTML("beforeend", "<%= j render(@user) %>"); -``` - -NOTE: JavaScript view rendering doesn't do any preprocessing, so you shouldn't use ES6 syntax here. - -Turbolinks ----------- - -Rails ships with the [Turbolinks library](https://github.com/turbolinks/turbolinks), -which uses Ajax to speed up page rendering in most applications. - -### How Turbolinks Works - -Turbolinks attaches a click handler to all `` tags on the page. If your browser -supports -[PushState](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history#The_pushState%28%29_method), -Turbolinks will make an Ajax request for the page, parse the response, and -replace the entire `` of the page with the `` of the response. It -will then use PushState to change the URL to the correct one, preserving -refresh semantics and giving you pretty URLs. - -If you want to disable Turbolinks for certain links, add a `data-turbolinks="false"` -attribute to the tag: - -```html -No turbolinks here. -``` - -### Page Change Events - -You'll often want to do some sort of processing upon -page load. Using the DOM, you'd write something like this: - -```js -window.addEventListener("load", () => { - alert("page has loaded!"); -}); -``` - -However, because Turbolinks overrides the normal page loading process, the -event that this relies upon will not be fired. If you have code that looks like -this, you must change your code to do this instead: - -```js -document.addEventListener("turbolinks:load", () => { - alert("page has loaded!"); -}); -``` - -For more details, including other events you can bind to, check out [the -Turbolinks -README](https://github.com/turbolinks/turbolinks/blob/master/README.md). - -Cross-Site Request Forgery (CSRF) token in Ajax ----- - -When using another library to make Ajax calls, it is necessary to add -the security token as a default header for Ajax calls in your library. To get -the token: - -```js -const token = document.getElementsByName( - "csrf-token" -)[0].content; -``` - -You can then submit this token as a `X-CSRF-Token` header for your -Ajax request. You do not need to add a CSRF token for GET requests, -only non-GET ones. - -You can read more about Cross-Site Request Forgery in the [Security guide](https://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf). - -Other Resources ---------------- - -Here are some helpful links to help you learn even more: - -* [rails-ujs wiki](https://github.com/rails/rails/tree/main/actionview/app/assets/javascripts) -* [Railscasts: Unobtrusive JavaScript](http://railscasts.com/episodes/205-unobtrusive-javascript) -* [Railscasts: Turbolinks](http://railscasts.com/episodes/390-turbolinks)