In this post, we will go through all the changes that are in the new 2.1.6 version.
Photo by Nick Karvounis on Unsplash
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 theturbolinks: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 missingX-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-levelrender_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 forturbolinks: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 documentstate 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.
Top comments (0)