render_async 2.1.6 released
Published Last updated loading views
In this post, we will go through all the changes that are in the new 2.1.6 version.
Some of the new changes and bug fixes were pretty tricky to solve. I wanted to write a blog post to have detailed hows and whys of how I fixed them.
The new version mainly brought bug fixes:
- Polling now stops when page navigates using Turbolinks
- Default header
X-Requested-With
is now set - Events delegate now works when toggling
- Nested partials now load with Turbolinks
Let us dive into details of how each was fixed:
Polling now stops when page navigates using Turbolinks
If you have not heard about Turbolinks before,
it is an excellent gimmick for your Rails application that makes it behave like a single-page
application. It gracefully avoids full page loads when you click a link, for
example. Turbolinks does this by fetching a page, swapping in its <body>
tag,
and merging its <head>
with existing content on the page. The gem has been well
adopted in the Rails world, and when you do rails new my-awesome-app
, it comes
equipped with Turbolinks gem from the start.
Before 2.1.6 version, if you used render_async’s polling feature, render_async did not handle navigation changes with Turbolinks. For example, if your page started polling and you clicked a link, it wouldn’t stop polling. The issue with polling sucked big time! Fortunately, in the new version, this is no more!
There is no more polling issue because we now call clearInterval
if the
turbolinks:visit
event happens:
$(document).one("turbolinks:visit", function () {
if (typeof _interval === "number") {
clearInterval(_interval)
_interval = undefined
}
})
Default header X-Requested-With
is now set
If you are using Vanilla JavaScript part of the gem (you don’t have jQuery in your
project, or you want Vanilla JS for some reason), each request was missing
X-Requested-With
header. This header is important and is set by jQuery by
default. It is set by default because some servers check this header as a
precaution from CSRF attacks. More about CSRF attack and X-Requested-With
header can be found in
this great blog post.
Fix was this was pretty easy and straightforward:
request.setRequestHeader("X-Requested-With", "XMLHttpRequest")
Event delegation now works when toggling
If you wanted to trigger the loading of render_async, you could use any element to do so. For example, you wanted to load comments on your blog with render_async you would so something like this:
<!-- app/views/posts/show.html.erb -->
<%= render_async comments_path, toggle: { selector: '#comments-button',
event: :click } do %>
<a href='#' id='comments-button'>Load comments</a>
<% end %>
The method above worked fine if you did not have any other events depending on that
link click. But issue occurred to one user when he tried
toggle feature on tabs
in his UI. He wanted to load content when the user was changing tabs in
his app. Line event.preventDefault()
inside toggle logic was stopping the changing of
tabs. Events did not delegate to the tab-changing logic, and the tab was never
changed. Fortunately, in the new 2.1.6 version, this is not happening anymore!
Nested partials now load with Turbolinks
Problem with nested partials was the last moment discovery by ye-ling-aung in his comment.
Nested partials did not load with Turbolinks. If, for some reason, you needed to
nest render_async calls into one another,
you could do it quickly. The problem occurred when the page loaded with Turbolinks. The top-level
render_async call got rendered, but the nested calls below did not. It was because render_async
loading logic is triggered when turbolinks:load
event gets triggered.
Triggering loading on turbolinks:load
is fine for the top-level (initial)
render_async call. But, if you have a nested call, it will wait for
turbolinks:load
, which will not happen, because the page already loaded.
In order to have nested calls render, I added a piece of logic which checks whether the document state is either ‘complete’ or ‘interactive’:
if (
document.readyState === "complete" ||
document.readyState === "interactive"
) {
// Call render_async rendering logic
}
This way, when initial render_async calls loads and renders nested calls, they are sure to be performed.
Final thoughts
Fixing and shipping these fixes was such a relief! I am thankful and glad for everyone that kept using render_async that were having these issues. I also hope that more people will try out the new version and report if they have any problems!
P.S. If you like my work on this gem so far, and you want me to keep improving and maintaining it, consider sponsoring me on GitHub Sponsors or through PayPal.
Join the newsletter!
Subscribe to get latest content by email and to become a fellow pineapple 🍍