Title: Dasherize, Turbolinks 3 and Parallel · Issue #5 · jollygoodcode/jollygoodcode.github.io · GitHub
Open Graph Title: Dasherize, Turbolinks 3 and Parallel · Issue #5 · jollygoodcode/jollygoodcode.github.io
X Title: Dasherize, Turbolinks 3 and Parallel · Issue #5 · jollygoodcode/jollygoodcode.github.io
Description: We open-sourced Dasherize a few days ago. Dasherize is a simple, material-designed dashboard for your projects on which you can see: CI status of master branch (supports Travis CI, Codeship and CircleCI) GitHub Pull Requests and Issues c...
Open Graph Description: We open-sourced Dasherize a few days ago. Dasherize is a simple, material-designed dashboard for your projects on which you can see: CI status of master branch (supports Travis CI, Codeship and Cir...
X Description: We open-sourced Dasherize a few days ago. Dasherize is a simple, material-designed dashboard for your projects on which you can see: CI status of master branch (supports Travis CI, Codeship and Cir...
Opengraph URL: https://github.com/jollygoodcode/jollygoodcode.github.io/issues/5
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Dasherize, Turbolinks 3 and Parallel","articleBody":"We open-sourced [Dasherize](http://github.com/jollygoodcode/dasherize) a few days ago.\n\n\u003ca href=\"http://www.dasherize.com\" target=\"_blank\"\u003e\u003cimg width=\"774\" alt=\"screenshot 2015-10-08 18 48 13\" src=\"https://cloud.githubusercontent.com/assets/1000669/10364359/280e45b0-6ded-11e5-96c3-4182d443a27e.png\"\u003e\u003c/a\u003e\n\nDasherize is a simple, material-designed dashboard for your projects on which you can see:\n- CI status of `master` branch (supports Travis CI, Codeship and CircleCI)\n- GitHub Pull Requests and Issues count and a peek of most recents\n\nMore importantly, Dasherize also has a presentation mode for big screen displays.\n\nThe [README](https://github.com/jollygoodcode/dasherize#origin) has more details of how Dasherize came about, so you can read that. \n\nThis blog post dives more into the technical details. \n## Turbolinks 3\n\nDasherize 3 uses [Turbolinks 3](https://github.com/rails/turbolinks) :tophat:. In fact, it's tracking `master` of Turbolinks now.\n\nSpecifically, it uses the [Partial Replacement](https://github.com/rails/turbolinks#partial-replacement-30) :sparkles: technique that's only available in Turbolinks 3.\n### Which Feature?\n\nTurbolinks is used to load each \"Card\" on the dashboard.\n\n\n### Code Walk Through\n\nWhen the dashboard loads, it first fills the dashboard with empty \"Cards\" (name only) for each project.\n\nThe code can be found in `app/views/projects/index.html.slim`, and the loop is:\n\n``` slim\n- if @projects.present?\n .row.mar-lg-top\n - @projects.each do |project|\n .col.s12.m4\n .project id=\"project:#{project.id}\"\n = link_to project_path(project), project_path(project), remote: true, class: 'hide js-project'\n\n .card-panel.no-padding.grey.darken-1\n .card-heading\n .card-title\n = link_to project.repo_name\n .right\n = link_to icon(\"gear\"), edit_project_path(project), class: \"gear\"\n .card-status.center.progress\n .indeterminate\n```\n\nThe important bit are the two lines below, while the rest are just markup that creates an empty \"Card\" with a progress bar.\n\n``` slim\n.project id=\"project:#{project.id}\"\n = link_to project_path(project), project_path(project), remote: true, class: 'hide js-project'\n```\n\nThe `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.\n\nNext, the anchor tag links to the `project_path(project)` which is a RESTful path to `projects#show` that shows (the \"Card\" for) one project.\n\nThe 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.\n\n``` javascript\n// app/assets/javascripts/projects.js\n\n$(\".js-project\").not('.in-progress').addClass('in-progress').click();\n```\n\nAs each link has `remote: true`, each click results in an async call to `projects#show` which looks like:\n\n``` ruby\n# app/controllers/projects_controller.rb\n\ndef show\n @project = ProjectDecorator.new(@project)\n @project.process_with(current_user.oauth_account.oauth_token)\n\n render change: \"project:#{@project.id}\"\nend\n```\n\nIf you noticed, the last line of the method `show` reads `render change: \"project:#{@project.id}\"`.\n\nLet's break it down:\n\n`render` with `change` instructs Turbolinks 3 to render the response (instead of doing a normal page load).\n\n`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`.\n\nAnd so, one by one, the empty \"Cards\" will be replaced by \"Cards\" with information.\n\nAs 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.\n\nThere is a potential problem which I am keeping track of though: \n\nhttps://github.com/rails/turbolinks/issues/546\n## Parallel ~~Tests~~\n\nYou are probably familiar with [Parallel Tests](https://github.com/grosser/parallel_tests) but not so much of the gem that powers it: [Parallel](https://github.com/grosser/parallel).\n\nIf 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.\n\nBack 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:\n\n``` ruby\n# app/controllers/projects_controller.rb\n\ndef show\n @project = ProjectDecorator.new(@project)\n @project.process_with(current_user.oauth_account.oauth_token)\n\n render change: \"project:#{@project.id}\"\nend\n```\n\nThe implementation of `process_with` is as follows:\n\n``` ruby\n# app/models/project_decorator\n\ndef process_with(oauth_token=nil)\n @oauth_token = oauth_token\n\n call_apis\nend\n```\n\nThe magic in this case happens in the private method `call_apis` which invokes other methods:\n\n``` ruby\ndef call_apis\n Parallel.each(api_functions, in_threads: api_functions.size) { |func| func.call }\nend\n\ndef api_functions\n [\n method(:init_repos),\n method(:init_ci)\n ]\nend\n\ndef init_repos\n client = Octokit::Client.new(access_token: @oauth_token)\n @_issues = client.issues(repo_name)\nend\n\ndef init_ci\n @_ci =\n case ci_type\n when \"travis\"\n Status::Travis.new(repo_name, travis_token).run!\n when \"codeship\"\n Status::Codeship.new(repo_name, codeship_uuid).run!\n when \"circleci\"\n Status::Circleci.new(repo_name, circleci_token).run!\n else\n Status::Null.new\n end\nend \n```\n\nIn 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. \n\n``` ruby\ndef call_apis\n Parallel.each(api_functions, in_threads: api_functions.size) { |func| func.call }\nend\n```\n\nUsing `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`.\n\nAs 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.\n## \n\nI had fun building Dasherize as a toy utility project. \n\nI hope you enjoyed reading about some of the technical details too. :blush: Thanks for reading! \n\n@winston :pencil2: [Jolly Good Code](http://www.jollygoodcode.com)\n### About Jolly Good Code\n\n[](http://www.jollygoodcode.com)\n\nWe specialise in Agile practices and Ruby, and we love contributing to open source. \n[Speak to us](http://www.jollygoodcode.com/#get-in-touch) about your next big idea, or [check out our projects](http://www.jollygoodcode.com/open-source). \n","author":{"url":"https://github.com/winston","@type":"Person","name":"winston"},"datePublished":"2015-10-08T10:37:04.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/5/jollygoodcode.github.io/issues/5"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:a0d1648e-7382-46fa-9061-05ec44439c38 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | B59A:1DE745:840FB8A:B37C623:6A5E7733 |
| html-safe-nonce | 438b9d67db1c25403a799d26004b3b44c29453c05d338d817861f0ab511d6a80 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCNTlBOjFERTc0NTo4NDBGQjhBOkIzN0M2MjM6NkE1RTc3MzMiLCJ2aXNpdG9yX2lkIjoiOTAxNjE1OTk1ODQ2NDM2MjI5MSIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | f2b3d4212ab5a3ce13655fdf3b5f7663e8d9993d8db37c031680d01fe09db1a3 |
| hovercard-subject-tag | issue:110420144 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/jollygoodcode/jollygoodcode.github.io/5/issue_layout |
| twitter:image | https://opengraph.githubassets.com/fe60926b167967b7594a039773c787a6e81616ebf239952ca7d6926c06b24b23/jollygoodcode/jollygoodcode.github.io/issues/5 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/fe60926b167967b7594a039773c787a6e81616ebf239952ca7d6926c06b24b23/jollygoodcode/jollygoodcode.github.io/issues/5 |
| og:image:alt | We open-sourced Dasherize a few days ago. Dasherize is a simple, material-designed dashboard for your projects on which you can see: CI status of master branch (supports Travis CI, Codeship and Cir... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | winston |
| hostname | github.com |
| expected-hostname | github.com |
| None | 71950bbe6bf7e15662b868c102fed9d1682c29a05970d9b2daa2e4dd3522c52e |
| turbo-cache-control | no-preview |
| go-import | github.com/jollygoodcode/jollygoodcode.github.io git https://github.com/jollygoodcode/jollygoodcode.github.io.git |
| octolytics-dimension-user_id | 5326832 |
| octolytics-dimension-user_login | jollygoodcode |
| octolytics-dimension-repository_id | 39484578 |
| octolytics-dimension-repository_nwo | jollygoodcode/jollygoodcode.github.io |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 39484578 |
| octolytics-dimension-repository_network_root_nwo | jollygoodcode/jollygoodcode.github.io |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 7514606601325843bc1c464d2d8bf5fe9af2c154 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width