Let’s understand why AJAX exists, so you can get a better idea of how to use it in your Rails projects.
When you visit a website, what happens?
A page is loaded from the server. But if you want to see new information you have to either reload the page to update it, or click a link to visit a different page.
This a synchronous flow.
New data is only presented when a new page is requested from the server.
But…
What if you don’t want this page reload?
What if you want to fetch data from the backend, any time you want, so that you can update any part of the current page?
This is where AJAX comes in.
AJAX stands for Asynchronous Javascript & XML.
It’s a technique that’s independent of your web framework, but Rails specifically has good support for it as you’ll learn in this article.
Keep in mind that adding AJAX into your app makes it more complex.
Direct AJAX Request
AJAX has two parts, the request, which you make from the browser using Javascript, and the response, which you handle from your Ruby app.
You can make an AJAX request with plain Javascript.
But because that requires a lot of boilerplate code we usually do this through a Javascript library like jQuery.
Here’s what a jQuery request looks like:
$.get( "/vegetables", function(data) { alert("Vegetables are good for you!"); });
However, since Rails 5.1 jQuery is not available by default (but you can add it back).
Note: You’ll get an
InvalidAuthenticityToken
error when you do a jQuery POST request, this means that you need to submit thecsrf-token
from the current page as a security measure. UsingRails.ajax
does this for you automatically.
There is a solution!
Rails includes its own AJAX function:
Rails.ajax({ url: "/books", type: "get", data: "", success: function(data) {}, error: function(data) {} })
Remember, this is still from the request side of things, from the browser.
Meaning that this is Javascript code.
In Rails, this AJAX functionality is provided by something called “Unobtrusive JavaScript”, or “UJS” for short.
Updating a Partial with AJAX
If you want to update only part of your page with the data you get from AJAX, you have mostly two options.
- You can write a Javascript + ERB view, which updates the element
- You can return a JSON response from your controller with the new HTML as a string, then use Javascript to update the element
There is also a 3rd option.
It involves returning only the data as JSON, then generating the HTML elements with Javascript using that data.
This is where JS frameworks like React come in.
In my opinion, they add a lot of unnecessary complexity.
But we can handle this with plain Javascript!
That’s options 1 & 2.
Let’s stick with those for now š
Javascript view example:
Rails.$('.random-number')[0].innerHTML = ("<%= j (render partial: 'random') %>")
j
is an alias forescape_javascript
jQuery example:
$('.random-number').html("<%= j (render partial: 'random') %>")
Both html
& innerHTML
replace the contents of the target element.
You could also append (jQuery) a new element into a list instead of replacing the whole thing.
Put this code in a file with an extension of .js.erb
, with the name of the current action (like create.js.erb
) & inside the views folder.
On the controller you can render this view just like any other view.
Now:
When you make an AJAX call, this Javascript code will run automatically & update the HTML.
Let’s have a look at the 2nd option.
Here’s the controller code:
render json: { html: render_to_string(partial: 'random') }
Then from your Javascript code:
Rails.ajax({ url: "/books", type: "get", success: function(data) { Rails.$(".random-number")[0].innerHTML = data.html; } })
That’s another way to do this!
What should you use?
DHH’s favorite is the first way, which he calls “SJR” (Server-Generated Javascript).
I guess this is how Rails wants you to do this, but feel free to try both (SJR
& render_to_string
) yourself & see which one works best for you.
How to Use HAML For Your JS Views
Ok.
Let’s say you’re a HAML user.
Is it possible to use this SJR
technique & render .js.haml
views?
Yes!
Here’s an example:
- content = j (render partial: "random") Rails.$('.random-number')[0].innerHTML = ("#{content}")
It’s a bit uglier than the ERB version, but it works.
How to Submit a Rails Form Without Refreshing The Page
If you want to submit a form using AJAX you can do this without having to write an AJAX request.
Rails can handle it for you.
How?
Use the remote: true
option with form_for
.
Here’s an example:
<%= form_for @fruit, remote: true do |f| %> <%= f.label :name, 'Fruit' %> <%= f.text_field :name %> <%= f.submit 'Create' %> <% end %>
Now when you click “Create” Rails will send an AJAX request for you & the page won’t reload.
If you want to display validation errors you’ll have to create & render a Javascript view (.js.erb
file) that replaces the current errors with the new errors.
Like the example in “Updating a Partial with AJAX”.
Btw, this remote
option can also be used with links, so you can do an AJAX delete
request.
Example:
<%= link_to "Delete", book_path(book), { method: "delete", remote: true, data: { confirm: "Are you sure?" } }
You can handle the response using a Javascript view.
If you want to handle both HTML requests (coming from a page reload) & AJAX request, you'll have to use something like the respond_to
method.
Example:
respond_to do |f| f.html { redirect_to :index } f.js end
In this example it may be easier to let Turbolinks handle this.
You can still do the AJAX requests & a redirect_to
from the controller (without respond_to
), then Turbolinks will replace the contents of the page without reloading it.
AJAX Not Working? Here Are Some Tips
If your AJAX request is not working then you have some debugging to do.
First, open your browser developer tools.
You want to look at the console panel for any Javascript errors.
Fix those.
Also, make sure that any CSS selector you're targeting is right & you don't have any typos.
Then, check your rails logs for any errors.
Then, make sure that the correct view is being rendered.
If you follow this process you should be able to find why your AJAX request is not working & fix it.
Summary
You have learned about AJAX, a web development technique that allows you to make Asynchronous Request!
You have also learned how to implement this in Rails. Remember that AJAX isn't required to make your regular (non-JS framework) Rails app work, but it's something that is helpful to have in your toolbox.
Don't forget to share this article so more people can benefit from it š
Thanks for reading!
How about an AJAX form example without remote: true ?
You would use
Rails.ajax
withPOST
as the type of request, thenRails.serializeElement(Rails.$("form")[0])
as the data.You can attach this code as a Javascript function on the
onsubmit
event.Everything else is the same, but I recommend using
remote: true
whenever possible to make things easier for you & follow best practices šThanks Jesus! Great read! Iām learning about AJAX now and your post above helped clear some things up. Much appreciated!
Thanks for reading! I’m glad you found it helpful š
Nice article! I know that you’re more of a Ruby guy Jesus but it would be really nice if we get more Rails articles like these š
Thanks for your support Tokara!
Yes, I enjoy Ruby itself more, but I know there is a need for good Rails content so I’m working on that š
Could you, please, post a full example for option #1? I am kind of lost in regards to what code to put where. Thanks!
Hi Martin,
I just made a fully working example for you.
https://github.com/matugm/rails5-ajax-example
Let me know if that helps š
Awesome, now I get it š Thanks!
Nevermind, I figured it out! lol, thanks! Your guide was helpful again.
Hi Chris, I’m glad you were able to figure it out š