{"id":153,"date":"2014-11-28T21:13:45","date_gmt":"2014-11-28T21:13:45","guid":{"rendered":"https:\/\/redbooth.com\/engineering\/?p=153"},"modified":"2015-07-28T18:28:02","modified_gmt":"2015-07-28T18:28:02","slug":"reinvent-collaboration-with-ruby","status":"publish","type":"post","link":"https:\/\/redbooth.com\/engineering\/technical\/reinvent-collaboration-with-ruby","title":{"rendered":"Reinvent collaboration\u2026 with ruby"},"content":{"rendered":"<p>Since the beginning of time, whenever a group of people work together, collaboration has been always something to improve. There is a bunch of collaboration software ready for helping you to do so, but what if you want to perform a specific idea you have? What if you want to improve your regular workflow a little bit or someone else&#8217;s workflow?<\/p>\n<p>Let\u2019s examine a specific case\u2026<\/p>\n<blockquote><p>\u201cI want to measure my team productivity hourly.\u201d<\/p><\/blockquote>\n<p>Well this might happen at a particular point in your company. Let\u2019s rethink the problem:<\/p>\n<p>we need to measure the amount of work\/activity our team generates in a determinate hour.<\/p>\n<p>So splitting the work we get:<\/p>\n<ul>\n<li>Retrieve project activity<\/li>\n<li>Group it by hour \/ day<\/li>\n<li>Represent it<\/li>\n<\/ul>\n<p>Is not that bad right?<\/p>\n<p>Let\u2019s say that your collaboration tool has a very good API ( <a href=\"https:\/\/platform.redbooth.com\">https:\/\/platform.redbooth.com<\/a> ). Let\u2019s say that there is an easy way to consume it ( <a href=\"https:\/\/github.com\/teambox\/redbooth-ruby\">https:\/\/github.com\/teambox\/redbooth-ruby<\/a> ) and also a very easy way to allow users connect with the service ( <a href=\"https:\/\/github.com\/teambox\/omniauth_redbooth\">https:\/\/github.com\/teambox\/omniauth_redbooth<\/a> ).<\/p>\n<p>Nice! let\u2019s start<\/p>\n<h3>Prepare the App and connect with Redbooth<\/h3>\n<p>For this specific case we will create a `rails 4` app. I don\u2019t want to go deeper in this process so I documented it for you so you can see how easy is to get to the sign-in with Redbooth point by using `devise` and `omniauth-redbooth`.<\/p>\n<p><a href=\"https:\/\/gist.github.com\/andresbravog\/f92229adb87c5d9d70a8\" title=\"Prepare the app\" target=\"_blank\">https:\/\/gist.github.com\/andresbravog\/f92229adb87c5d9d70a8<\/a><\/p>\n<p>After following these quick steps and a little bit of css magic we already have something like this:<\/p>\n<p><a href=\"https:\/\/s3.amazonaws.com\/wordpress-production\/wp-content\/uploads\/sites\/7\/2014\/11\/root-app.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/s3.amazonaws.com\/wordpress-production\/wp-content\/uploads\/sites\/7\/2014\/11\/root-app-1024x583.png\" alt=\"root-app\" width=\"1024\" height=\"583\" class=\"alignnone size-large wp-image-144\" style=\"padding: 0;\" srcset=\"https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/root-app-1024x583.png 1024w, https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/root-app-300x170.png 300w, https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/root-app.png 1348w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>In order to get Redbooth data we just need to consume the data. That\u2019s pretty easy to do by using the `redbooth-ruby` gem.<\/p>\n<p>Adding the gem to our Gemfile<\/p>\n<pre>gem 'redbooth-ruby'<\/pre>\n<p>This makes it easy to consume redbooth data via API.<\/p>\n<h2>Showing a project picker<\/h2>\n<p>Graphing the activity of every Redbooth project would be a little bit misleading so we are going to create a project selector to reduce the visualization scope. In order to do so we need to fetch the Rebooth projects name\/id list to which the user belongs.<\/p>\n<p>I recommend using service objects to perform the different operations inside your applications. Here is one retrieving the projects list:<\/p>\n<pre>\r\nclass RedboothConnector::ProjectsLister\r\n  attr_accessor :user\r\n \r\n  def initialize(user)\r\n    @user = user\r\n  end\r\n \r\n  # Fetches all Redbooth projects where user belongs\r\n  #\r\n  # @return [Array(RedboothRuby::Project)]\r\n  def perform\r\n   projects_collection = client.project(:index, user_id: user_id)\r\n   projects = projects_collection.all\r\n  \r\n   while projects_collection = projects_collection.next_page do\r\n    projects &lt;&lt; projects_collection.all\r\n   end\r\n  \r\n   projects.flatten!\r\n  end\r\n \r\n  protected\r\n  \r\n  # Current user id\r\n  #\r\n  # @return [Integer]\r\n  def user_id\r\n   client.me(:show).id\r\n  end\r\n  \r\n  def session\r\n   @session ||= ::RedboothRuby::Session.new(token: user.credentials.token)\r\n  end\r\n  \r\n  def client\r\n   @client ||= ::RedboothRuby::Client.new(session)\r\n  end\r\nend\r\n<\/pre>\n<p>As you can see we initialize the service object with the user holding the authentication data that we are going to use to create the redbooth-ruby session and client. All this initialization data could be extracted to a Base object like:<\/p>\n<pre>\r\nrequire 'redbooth-ruby'\r\n\r\nclass RedboothConnector::Base\r\n  attr_accessor :user\r\n  \r\n  # Initializes the Ruby object with the user holding\r\n  # the redbooth credentials\r\n  #\r\n  # @param user [User] user holding the redbooth credentials\r\n  def initialize(user)\r\n    @user = user\r\n  end\r\n \r\n  protected\r\n  \r\n  # Creates RedboothRuby session based on user credentials\r\n  #\r\n  # @return [RedboothRuby::Session]\r\n  def session\r\n    @session ||= ::RedboothRuby::Session.new(token: user.credentials.token)\r\n  end\r\n  \r\n  # Creates RedboothRuby client based on the session\r\n  #\r\n  # @return [RedboothRuby::Client]\r\n  def client\r\n    @client ||= ::RedboothRuby::Client.new(session)\r\n  end\r\nend\r\n<\/pre>\n<p>Now we can have a much cleaner project retriever object by keeping only the perform method to collect the user projects and the user_id helper.<\/p>\n<pre>\r\nclass RedboothConnector::ProjectsLister &lt; RedboothConnector::Base\r\n \r\n  # Fetches all Redbooth projects where user belongs\r\n  #\r\n  # @return [Array(RedboothRuby::Project)]\r\n  def perform\r\n    projects_collection = client.project(:index, user_id: user_id)\r\n    projects = projects_collection.all\r\n \r\n    while projects_collection = projects_collection.next_page do\r\n      projects &lt;&lt; projects_collection.all\r\n    end\r\n \r\n    projects.flatten!\r\n  end\r\n \r\n  protected\r\n \r\n  # Current user id\r\n  #\r\n  # @return [Integer]\r\n  def user_id\r\n    client.me(:show).id\r\n  end\r\n \r\nend\r\n<\/pre>\n<p>And use it in your controller like<\/p>\n<pre>\r\n@projects = RedboothConnector::ProjectsLister.new(@current_user).perform\r\n<\/pre>\n<p>And with a little bit of css magic we can do the second step of our app: a project selector.<\/p>\n<p><a href=\"https:\/\/s3.amazonaws.com\/wordpress-production\/wp-content\/uploads\/sites\/7\/2014\/11\/project-selector.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/s3.amazonaws.com\/wordpress-production\/wp-content\/uploads\/sites\/7\/2014\/11\/project-selector-1024x594.png\" alt=\"project-selector\" width=\"1024\" height=\"594\" class=\"alignnone size-large wp-image-145\" style=\"padding: 0;\" srcset=\"https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/project-selector-1024x594.png 1024w, https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/project-selector-300x174.png 300w, https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/project-selector.png 1322w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>But, let\u2019s get back to the point.<\/p>\n<h2>Retrieve project activity<\/h2>\n<p>Once the user has selected the target project to be represented we are able to start retrieving the project activity which in this example will be the task creation count grouped by hour and week day. As we have the Base redbooth connector object holding the common client logic we are going to create a service object wrapping that:<\/p>\n<pre>\r\nclass RedboothConnector::TasksDataGrouper &lt; RedboothConnector::Base\r\n  attr_accessor :project_id, :data\r\n  \r\n  # Initializes the Object attributes with targeted redbooth project_id\r\n  # \r\n  # @param user [User] user holding redbooth credentials\r\n  # @param project_id [Integer] Redbooth project id to list task form\r\n  def initialize(user, project_id)\r\n    @project_id = project_id\r\n    @data = {}\r\n    super(user)\r\n  end\r\n  \r\n  def perform\r\n    tasks_collection = client.task(:index, project_id: project_id)\r\n \r\n    parse_tasks_data(tasks_collection.all)\r\n \r\n    while tasks_collection = tasks_collection.next_page do\r\n      parse_tasks_data(tasks_collection.all)\r\n    end\r\n \r\n    to_hash\r\n  end\r\n \r\n  protected\r\n  \r\n  # Group given tasks data by creation hour and week day \r\n  # and hold that count info into @data attribute\r\n  def parse_tasks_data(tasks)\r\n    tasks.each do |task|\r\n      # ...\r\n    end\r\n  end\r\n  \r\n  # Export @data info into a understandable graph info\r\n  #\r\n  # @return [Array]\r\n  def to_graph\r\n    # ...\r\n  end\r\nend\r\n<\/pre>\n<p>Here we are iterating over the pages and parsing that data, this is good for two different reasons, it keeps our process memory in a controlled level and it gives us the ability to \u201cguess\u201d how much time this process is going to take so we can get the total_pages information.<\/p>\n<p>Once we retreive this data we just have to describe the data visually by using any chart library you love, here we are using highcharts.com.<\/p>\n<pre>\r\n@data = RedboothConnector::TasksDataGrouper.new(current_user, params[:project_id]).perform.to_graph\r\n<\/pre>\n<p><a href=\"https:\/\/s3.amazonaws.com\/wordpress-production\/wp-content\/uploads\/sites\/7\/2014\/11\/puch-card.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/s3.amazonaws.com\/wordpress-production\/wp-content\/uploads\/sites\/7\/2014\/11\/puch-card-1024x798.png\" alt=\"puch-card\" width=\"1024\" height=\"798\" class=\"alignnone size-large wp-image-146\" style=\"padding: 0;\" srcset=\"https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/puch-card-1024x798.png 1024w, https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/puch-card-300x234.png 300w, https:\/\/wordpress-production.s3.amazonaws.com\/wp-content\/uploads\/sites\/7\/2014\/11\/puch-card.png 1310w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<h2>Wrap up<\/h2>\n<p>By now you should have an idea on how to build new features in top of any collaboration platform (especially Redbooth one).<\/p>\n<p>You also should know how to easily connect your application users with Redbooth API and how to fetch and iterare over the different Redbooth objects and data.<\/p>\n<p>So, now that you have the ability to build something new, and improve collaboration, What are you going to create?<\/p>\n<h2>Links<\/h2>\n<ul>\n<li>Live App: <a href=\"https:\/\/redbooth-punch-card.herokuapp.com\" title=\"Live App\" target=\"_blank\">https:\/\/redbooth-punch-card.herokuapp.com<\/a><\/li>\n<li>Github Repo: <a href=\"https:\/\/redbooth-punch-card.herokuapp.com\" title=\"Github Repo\" target=\"_blank\">https:\/\/github.com\/andresbravog\/redbooth-punch-card<\/a><\/li>\n<li>Redbooth-Omniauth: <a href=\"https:\/\/github.com\/teambox\/omniauth-redbooth\" title=\"Redbooth-Omniauth\" target=\"_blank\">https:\/\/github.com\/teambox\/omniauth-redbooth<\/a><\/li>\n<li>Redbooth-Ruby: <a href=\"https:\/\/github.com\/teambox\/redbooth-ruby\" title=\"Redbooth-Ruby\" target=\"_blank\">https:\/\/github.com\/teambox\/redbooth-ruby<\/a><\/li>\n<li>HighCharts: <a href=\"http:\/\/www.highcharts.com\" title=\"Highcharts\" target=\"_blank\">http:\/\/www.highcharts.com<\/a><\/li>\n<\/ul>\n<p>Thanks and happy coding<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Since the beginning of time, whenever a group of people work together, collaboration has been always something to improve. There is a bunch of collaboration software ready for helping you to do so, but what if you want to perform a specific idea you have? What if you want to improve your regular workflow a <a class=\"read-more\" href=\"https:\/\/redbooth.com\/engineering\/technical\/reinvent-collaboration-with-ruby\">&hellip;&nbsp;<span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":49,"featured_media":143,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,24,7],"tags":[29,48,30,28],"class_list":["post-153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-platform","category-ruby","category-technical","tag-omniauth","tag-platform","tag-punch-card","tag-ruby-2"],"_links":{"self":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts\/153","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/users\/49"}],"replies":[{"embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/comments?post=153"}],"version-history":[{"count":0,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts\/153\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/media\/143"}],"wp:attachment":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/media?parent=153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/categories?post=153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/tags?post=153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}