From 4d0c43e66c112d551eb8a167a35ddf2d7866fcc0 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 30 Aug 2012 19:39:49 -0700 Subject: Working With JavaScript guide. Originally, this guide was called "AJAX on Rails," but really, it's not just about AJAX. This was never finished, but it got accidentally generated and Google found out about it. In the meantime, all the guides were converted to markdown, as well. So here's a new guide. It covers all of the built-in helpers that use ajax requests, it covers CoffeeScript, and it covers UJS. --- guides/source/working_with_javascript.md | 392 +++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 guides/source/working_with_javascript.md (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md new file mode 100644 index 0000000000..1fabb9b99e --- /dev/null +++ b/guides/source/working_with_javascript.md @@ -0,0 +1,392 @@ +Working With JavaScript +======================= + +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! We will cover the following topics: + +* Quick introduction to AJAX +* Unobtrusive JavaScript +* How Rails' built-in helpers assist you +* Handling AJAX on the server side +* The Turbolinks gem + +------------------------------------------------------------------------------- + +An introduction to AJAX +------------------------ + +In order to understand AJAX, you must first understand what a web broswer does +normally. + +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.' + +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. + +Rails ships with CoffeeScript by default, and so the rest of the examples +in this guide will be in CoffeeScript. All of these lessons, of course, apply +to vanilla JavaScript as well. + +As an example, here's some CoffeeScript code that makes an AJAX request using +the jQuery library: + +``` +$.ajax(url: "/test").done (html) -> + $("#results").append html +``` + +This code fetches data from "/test", and then appends the result to the `div` +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 web sites in this manner, 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': + +``` +Here +``` + +When clicked, the alert will trigger. Here's the problem: what happens when +we have lots of JavaScript we want to execute on a click? + +``` +Calculate +``` + +Awkward, right? We could pull the function definition out of the click handler, +and turn it into CoffeeScript: + +``` +fib = (n) -> + (if n < 2 then n else fib(n - 1) + fib(n - 2)) +``` + +And then on our page: + +``` +Calculate +``` + +That's a little bit better, but what about multiple links that have the same +effect? + +``` +Calculate +Calculate +Calculate +``` + +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: + +``` +fib = (n) -> + (if n < 2 then n else fib(n - 1) + fib(n - 2)) + +$(document).ready -> + $("a[data-fib]").click (e) -> + count = $(this).data("fib") + alert "fib of #{count} is: #{fib(count)}." + +... later ... + +Calculate +Calculate +Calculate +``` + +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. + +The Rails team strongly encourages you to write your CoffeeScript (and +JavaScript) in this style, and you can expect that many libraries will also +follow this pattern. + +Built-in Helpers +---------------------- + +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. + +Because of Unobtrusive JavaScript, the Rails "AJAX helpers" are actually in two +parts: the JavaScript half and the Ruby half. +[rails.js](https://github.com/rails/jquery-ujs/blob/master/src/rails.js) +provides the JavaScript half, and the regular Ruby view helpers add appropriate +tags to your DOM. The CoffeeScript in rails.js then listens for these +attributes, and attaches appropriate handlers. + +### form_for + +[`form_for`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for) +is a helper that assists with writing `
`s. `form_for` takes a `:remote` +option. It works like this: + +``` +<%= form_for(@post, remote: true) do |f| %> + ... +<% end %> +``` + +This will generate the following HTML: + +``` + + ... +
+``` + +Note the `data-remote='true'`. Now, the form will be submitted by AJAX rather +than by the browser's normal submit mechanism. + +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: + +``` + +``` + +Obviously, you'll want to be a bit more sophisticated than that, but it's a +start. + +### form_tag + +[`form_tag`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-form_tag) +is very similar to `form_for`. It has a `:remote` option that you can use like +this: + +``` +<%= form_tag('/posts', remote: true) %> +``` + +Everything else is the same as `form_for`. See its documentation for full +details. + +### link_to + +[`link_to`](http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to) +is a helper that assits with generating links. It has a `:remote` option you +can use like this: + +``` +<%= link_to "first post", @post, remote: true %> +``` + +which generates + +``` +a post +``` + +You can bind to the same AJAX events as `form_for`. Here's an example. Let's +assume that we have a resource `/fib/:n` that calculates the `n`th Fibonacci +number. We would generate some HTML like this: + +<%= link_to "Calculate", "/fib/15", remote: true, data: { fib: 15 } %> + +and write some CoffeeScript like this: + +``` +$(document).ready -> + $("a[data-fib]").on "ajax:success", (e, data, status, xhr) -> + count = $(this).data("fib") + alert "fib of #{count} is: #{data}." +``` + +Easy! + +### button_to + +[`button_to`](http://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: + +``` +<%= button_to "A post", @post, remote: true %> +``` + +this generates + +``` + +
+``` + +Since it's just a `
`, all of the information on `form_for` also applies. + +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: + +``` +class UsersController < ApplicationController + def index + @users = User.all + @user = User.new + end + # ... +``` + +The index view (`app/views/users/index.html.erb`) contains: + +``` +Users + + + +
+ +<%= form_for(@user, remote: true) do |f| %> + <%= f.label :name %>
+ <%= f.text_field :name %> + <%= f.submit %> +<% end %> +``` + +The `app/views/users/_user.html.erb` partial contains the following: + +``` +
  • <%= 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 Users controller. Because +the form's remote option is set to true, the request will be posted to the +users controller as an AJAX request, looking for JavaScript. In order to +service that request, the create action of your controller would look like +this: + +``` + # 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. + +``` +$("<%= escape_javascript(render @user) %>").appendTo("#users"); +``` + +Turbolinks +---------- + +Rails 4 ships with the [Turbolinks gem](https://github.com/rails/turbolinks). +This gem uses AJAX to speed up page rendering in most applications. + +### How Turbolinks works + +Turbolinks attaches a click handler to all `` on the page. If your browser +supports +[PushState](https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history#The_pushState(\).C2.A0method), +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. + +The only thing you have to do to enable Turbolinks is have it in your Gemfile, +and put `//= require turbolinks` in your CoffeeScript manifest, which is usually +`app/assets/javascripts/application.js`. + +If you want to disable Turbolinks for certain links, add a `data-no-turbolink` +attribute to the tag: + +``` +No turbolinks here. +``` + +### Page Change events + +When writing CoffeeScript, you'll often want to do some sort of processing upon +page load. With jQuery, you'd write something like this: + +``` +$(document).ready -> + alert "page has loaded!" +``` + +However, because Turbolinks overrides the normal page loading process, the +event that this relies on will not be fired. If you have code that looks like +this, you must change your code to do this instead: + +``` +$(document).on "page:change", -> + alert "page has loaded!" +``` + +For more details, including other events you can bind to, check out [the +Turbolinks +README](https://github.com/rails/turbolinks/blob/ec9ca4d6cf9626e03a672f3b9e7968c816aff94e/README.md). + +Other resources +--------------- + +Here are some helpful links to help you learn even more: + +* [jquery-ujs wiki](https://github.com/rails/jquery-ujs/wiki) +* [jquery-ujs list of external articles](https://github.com/rails/jquery-ujs/wiki/External-articles) +* [Rails 3 Remote Links and Forms: A Definitive Guide](http://www.alfajango.com/blog/rails-3-remote-links-and-forms/) +* [Railscasts: Unobtrusive JavaScript](http://railscasts.com/episodes/205-unobtrusive-javascript) -- cgit v1.2.3 From 6d927fb4da7a0a17d62109b7ef8798a8e75082a7 Mon Sep 17 00:00:00 2001 From: Agis Anastasopoulos Date: Sun, 21 Oct 2012 17:06:47 +0300 Subject: fix a typo --- guides/source/working_with_javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index 1fabb9b99e..9a2c6e4df0 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -20,7 +20,7 @@ In order to understand AJAX, you must first understand what a web broswer does normally. 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 +'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, -- cgit v1.2.3 From 506257a173bb5cbb083ccae8d1b4ed82a456006a Mon Sep 17 00:00:00 2001 From: Agis Anastasopoulos Date: Sun, 21 Oct 2012 17:10:11 +0300 Subject: Consistent headlines & ToC I believe the topics and their headlines should be consistent for obvious reasons. Also --- guides/source/working_with_javascript.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index 9a2c6e4df0..2099826add 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -5,11 +5,11 @@ 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! We will cover the following topics: -* Quick introduction to AJAX +* An introduction to AJAX * Unobtrusive JavaScript -* How Rails' built-in helpers assist you -* Handling AJAX on the server side -* The Turbolinks gem +* Built-in Helpers +* Server-side concerns +* Turbolinks ------------------------------------------------------------------------------- @@ -246,7 +246,7 @@ this generates Since it's just a ``, all of the information on `form_for` also applies. -Server side concerns +Server-side concerns -------------------- AJAX isn't just client-side, you also need to do some work on the server -- cgit v1.2.3 From a6d383c8b2afb253c009ad67d31aae3aa8dcc457 Mon Sep 17 00:00:00 2001 From: Agis Anastasopoulos Date: Sun, 21 Oct 2012 17:12:05 +0300 Subject: Improve "request response" term typing & fix a minor typo --- guides/source/working_with_javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index 2099826add..c0220017d3 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -24,7 +24,7 @@ When you type `http://localhost:3000` into your browser's address bar and hit 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.' +show you the results. This is called the 'Request-Response cycle'. 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 -- cgit v1.2.3 From 1332cf53af981d0a7a6f801edd9632eb5c118a3f Mon Sep 17 00:00:00 2001 From: Agis Anastasopoulos Date: Sun, 21 Oct 2012 17:15:44 +0300 Subject: Explain where the acronym AJAX stands for & replace "JavaScript writer" with "JavaScript developer" --- guides/source/working_with_javascript.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index c0220017d3..ece3b7647c 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -28,9 +28,9 @@ show you the results. This is called the 'Request-Response cycle'. 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 +powers, a JavaScript developer 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. +powerful technique that we call AJAX, which stands for Asynchronous JavaScript and XML. Rails ships with CoffeeScript by default, and so the rest of the examples in this guide will be in CoffeeScript. All of these lessons, of course, apply -- cgit v1.2.3 From 507e522e26b4073455b2337bcf1670e52bba5429 Mon Sep 17 00:00:00 2001 From: Agis Anastasopoulos Date: Sun, 21 Oct 2012 17:19:06 +0300 Subject: Improve grammar a bit --- guides/source/working_with_javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index ece3b7647c..7ec489f23a 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -119,7 +119,7 @@ $(document).ready -> 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 +changes easier. 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 -- cgit v1.2.3 From 00332733b2bf83b22dd57a18a5a61217ce7cfe5f Mon Sep 17 00:00:00 2001 From: Agis Anastasopoulos Date: Sun, 21 Oct 2012 17:21:50 +0300 Subject: Improve grammar --- guides/source/working_with_javascript.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index 7ec489f23a..dba6a68940 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -136,8 +136,8 @@ 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. -Because of Unobtrusive JavaScript, the Rails "AJAX helpers" are actually in two -parts: the JavaScript half and the Ruby half. +Because of Unobtrusive JavaScript, the Rails AJAX helpers actually consist of two +parts: the JavaScript part and the Ruby part. [rails.js](https://github.com/rails/jquery-ujs/blob/master/src/rails.js) provides the JavaScript half, and the regular Ruby view helpers add appropriate tags to your DOM. The CoffeeScript in rails.js then listens for these -- cgit v1.2.3 From 2767f01be05e3714b250f8c2743b7f5e1b0833ac Mon Sep 17 00:00:00 2001 From: Agis Anastasopoulos Date: Sun, 21 Oct 2012 17:23:22 +0300 Subject: Fix a typo --- guides/source/working_with_javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index dba6a68940..2758564a93 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -146,7 +146,7 @@ attributes, and attaches appropriate handlers. ### form_for [`form_for`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for) -is a helper that assists with writing ``s. `form_for` takes a `:remote` +is a helper that assists with writing forms. `form_for` takes a `:remote` option. It works like this: ``` -- cgit v1.2.3 From d279d3e165de1bcdb51fd673e043f2c68d21501d Mon Sep 17 00:00:00 2001 From: Robin Dupret Date: Sun, 21 Oct 2012 17:48:40 +0300 Subject: Wrap a piece of code to a code block --- guides/source/working_with_javascript.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index 2758564a93..cbdf5c79de 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -216,7 +216,9 @@ You can bind to the same AJAX events as `form_for`. Here's an example. Let's assume that we have a resource `/fib/:n` that calculates the `n`th Fibonacci number. We would generate some HTML like this: +``` <%= link_to "Calculate", "/fib/15", remote: true, data: { fib: 15 } %> +``` and write some CoffeeScript like this: -- cgit v1.2.3 From 67ec9b7c4e63e3597859440e2a2e4c5c71dbd875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lennart=20Fride=CC=81n?= Date: Sun, 21 Oct 2012 17:36:02 +0200 Subject: Fixes typo. --- guides/source/working_with_javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guides/source/working_with_javascript.md') diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md index cbdf5c79de..c33fa8864c 100644 --- a/guides/source/working_with_javascript.md +++ b/guides/source/working_with_javascript.md @@ -16,7 +16,7 @@ ease! We will cover the following topics: An introduction to AJAX ------------------------ -In order to understand AJAX, you must first understand what a web broswer does +In order to understand AJAX, you must first understand what a web browser does normally. When you type `http://localhost:3000` into your browser's address bar and hit -- cgit v1.2.3