You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The id is important because this is the id to be used for Turbolinks Partial Replacement, so that a specific .project can be swapped out with a server response.
Next, the anchor tag links to the project_path(project) which is a RESTful path to projects#show that shows (the "Card" for) one project.
The magic happens with remote: true and some JavaScript. When the page loads, JavaScript will trigger a click on all the anchor tags with .js-project class.
If you noticed, the last line of the method show reads render change: "project:#{@project.id}".
Let's break it down:
render with change instructs Turbolinks 3 to render the response (instead of doing a normal page load).
change: "project:#{@project.id}" instructs Turbolinks 3 to replace only the div with a matching id that can be found in the rendering app/views/projects/show.html.slim.
And so, one by one, the empty "Cards" will be replaced by "Cards" with information.
As of this writing, Turbolinks 3's Partial Replacement technique looks really promising to me. In fact, before Turbolinks 3, I would write custom JS that sort of mimics the behavior of Partial Replacement. Hence I am really looking forward to the release of Turbolinks 5 as that means I don't need to write extra JS anymore.
There is a potential problem which I am keeping track of though:
You are probably familiar with Parallel Tests but not so much of the gem that powers it: Parallel.
If you look into the source code, you will notice that I am actually not storing anything in the database (except for projects). Hence in order to make API calls ((GitHub + CI) * Number of Projects) speedy, Parallel is used to parallelize the API calls.
Back to app/controllers/projects_controller.rb again, where we first instantiate a ProjectDecorator, then we invoke process_with with the user's GitHub OAuth token:
In the method call_apis, Parallel was used to fork 2 threads (api_functions.size), and to split and execute the methods in api_functions in separate threads.
Using method(:init_repos) and method(:init_ci), these two methods become function pointers that we can pass it as arguments to Parallel.each and be eventually invoked with func.call.
As such, to call both GitHub and CI apis for a project, no waiting is required to make the two api calls. With Parallel, it helped to reduce the time required for making all API calls, and thus made the dashboard load speedily.
I had fun building Dasherize as a toy utility project.
I hope you enjoyed reading about some of the technical details too. 😊 Thanks for reading!
We open-sourced Dasherize a few days ago.
Dasherize is a simple, material-designed dashboard for your projects on which you can see:
master
branch (supports Travis CI, Codeship and CircleCI)More importantly, Dasherize also has a presentation mode for big screen displays.
The README has more details of how Dasherize came about, so you can read that.
This blog post dives more into the technical details.
Turbolinks 3
Dasherize 3 uses Turbolinks 3 🎩. In fact, it's tracking
master
of Turbolinks now.Specifically, it uses the Partial Replacement ✨ technique that's only available in Turbolinks 3.
Which Feature?
Turbolinks is used to load each "Card" on the dashboard.
Code Walk Through
When the dashboard loads, it first fills the dashboard with empty "Cards" (name only) for each project.
The code can be found in
app/views/projects/index.html.slim
, and the loop is:The important bit are the two lines below, while the rest are just markup that creates an empty "Card" with a progress bar.
The
id
is important because this is theid
to be used for Turbolinks Partial Replacement, so that a specific.project
can be swapped out with a server response.Next, the anchor tag links to the
project_path(project)
which is a RESTful path toprojects#show
that shows (the "Card" for) one project.The magic happens with
remote: true
and some JavaScript. When the page loads, JavaScript will trigger a click on all the anchor tags with.js-project
class.As each link has
remote: true
, each click results in an async call toprojects#show
which looks like:If you noticed, the last line of the method
show
readsrender change: "project:#{@project.id}"
.Let's break it down:
render
withchange
instructs Turbolinks 3 to render the response (instead of doing a normal page load).change: "project:#{@project.id}"
instructs Turbolinks 3 to replace only thediv
with a matchingid
that can be found in the renderingapp/views/projects/show.html.slim
.And so, one by one, the empty "Cards" will be replaced by "Cards" with information.
As of this writing, Turbolinks 3's Partial Replacement technique looks really promising to me. In fact, before Turbolinks 3, I would write custom JS that sort of mimics the behavior of Partial Replacement. Hence I am really looking forward to the release of Turbolinks 5 as that means I don't need to write extra JS anymore.
There is a potential problem which I am keeping track of though:
turbolinks/turbolinks-classic#546
Parallel
TestsYou are probably familiar with Parallel Tests but not so much of the gem that powers it: Parallel.
If you look into the source code, you will notice that I am actually not storing anything in the database (except for projects). Hence in order to make API calls (
(GitHub + CI) * Number of Projects
) speedy,Parallel
is used to parallelize the API calls.Back to
app/controllers/projects_controller.rb
again, where we first instantiate aProjectDecorator
, then we invokeprocess_with
with the user's GitHub OAuth token:The implementation of
process_with
is as follows:The magic in this case happens in the private method
call_apis
which invokes other methods:In the method
call_apis
,Parallel
was used to fork 2 threads (api_functions.size
), and to split and execute the methods inapi_functions
in separate threads.Using
method(:init_repos)
andmethod(:init_ci)
, these two methods become function pointers that we can pass it as arguments toParallel.each
and be eventually invoked withfunc.call
.As such, to call both GitHub and CI apis for a project, no waiting is required to make the two api calls. With
Parallel
, it helped to reduce the time required for making all API calls, and thus made the dashboard load speedily.I had fun building Dasherize as a toy utility project.
I hope you enjoyed reading about some of the technical details too. 😊 Thanks for reading!
@winston ✏️ Jolly Good Code
About Jolly Good Code
We specialise in Agile practices and Ruby, and we love contributing to open source.
Speak to us about your next big idea, or check out our projects.
The text was updated successfully, but these errors were encountered: