How to Add DEV Comments to Your Orbit Workspace With Ruby
Tags: ruby, tutorial
Published: 2021-04-27 07:11:16

---
title: How to Add DEV Comments to Your Orbit Workspace With Ruby
published: true
description: A step by step guide to bringing DEV blog post comments into your Orbit workspace with the DEV and Orbit APIs and Ruby
tags: ruby, tutorial
cover_image: https://cdn.sanity.io/images/cad8jutx/production/6e30e011837bd84213688e20bac9cdae5b709793-1220x694.png
canonical_url: https://orbit.love/blog/how-to-add-dev-comments-to-your-orbit-workspace/
---

The DEV community has become one of the fastest-growing developer blogging platforms. Whether you are posting primarily on the DEV blog or cross-posting your content there from your primary content source, keeping on top of the comments left by users is critical. Few things can be more frustrating to someone trying to engage than receiving no response.

In this step-by-step tutorial, we are going to use both the DEV API and the Orbit API to retrieve blog post comments and add them as a custom activity into Orbit.

![Example of DEV comment added to Orbit](https://cdn.sanity.io/images/cad8jutx/production/da87ad97dddd6ea8f7178d47b93c930b2899172e-1030x200.png)

_tl;dr If you wish to skip the tutorial, the entire code for this project as a Ruby gem that can be installed in your project can be found on [GitHub](https://github.com/bencgreenberg/dev_orbit)._

## Prerequisites

You will need the following to complete the steps in this tutorial:

-   Ruby 2.7 or greater installed locally.
-   An Orbit account. If you don’t have one already, you can [sign up today](https://app.orbit.love/signup) and start building with the Orbit API. Once you have an account, you can find your API Token in your Account Settings.
-   A [DEV Community](https://dev.to/enter?state=new-user) account. Once you have your DEV account, you can generate an API Key in your [Account Settings](https://dev.to/settings/account).

## Connecting to the DEV API

There are two separate API endpoints we need to access on the DEV API in order to get our blog posts comments. Namely, we need to retrieve a list of our articles, and then, we need to retrieve the comments for each article.

### Get List of Published Articles

The first operation, [GET Published Articles](https://docs.forem.com/api/#operation/getArticles), accepts several query parameters. We will be using the `username` parameter. The `username` parameter allows us to narrow our article search for a specific user's articles.

The following is the HTTP request for our DEV articles:

```ruby
url = URI("https://dev.to/api/articles?username=#{@username}")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true

request = Net::HTTP::Get.new(url)

response = https.request(request)

articles = JSON.parse(response.body)
```

In your code, replace `#{@username}` with the username of the DEV user you are searching for.

We are now ready to use the `articles` list to retrieve the comments for each article.

### Get Comments for Each Article

Once we have our list of articles from DEV, we can go ahead and access the next DEV API endpoint of [`GET Comments by Article ID`](https://docs.forem.com/api/#operation/getCommentsByArticleId). This endpoint requires the article ID as a query parameter.

We will build an iterator in our code to loop through the list of articles and request the comments for each one:

```ruby
comments = articles.each do |article|
  get_article_comments(article["id"])
end

def get_article_comments(id)
  url = URI("https://dev.to/api/comments?a_id=#{id}")
  https = Net::HTTP.new(url.host, url.port)
  https.use_ssl = true

  request = Net::HTTP::Get.new(url)

  response = https.request(request)

  comments = JSON.parse(response.body)

  return if comments.nil? || comments.empty?

  filter_comments(comments)
end
```

First, we iterate through each article in `articles` invoking a method called `#get_article_comments` passing in the article's ID as the method's parameter.

Next, we create the `#get_article_comments` method. The method makes an HTTP request to the DEV API endpoint. At the end of the method, we execute another method that we have not yet created called `#filter_comments`. Inside this next method, we can add any sort of `datetime` filtering we want to the data as a way to limit the scope if we are working with a lot of DEV blog post comments. In the following example, I restrict the data set to anything less than or equal to one day ago:

```ruby
def filter_comments(comments)
  comments.select do |comment|
    comment["created_at"] <= 1.day.ago
  end
end
```

> Note: The `1.day.ago` functionality in the code snippet above comes from ActiveSupport. To take advantage of it you need to add `require "active_support/time"` at the top of your Ruby script.

We now have all of the comments that we want to add as custom activities to our Orbit workspace! Let's go ahead and start doing that.

## Working with the Orbit API

The Orbit API lets you perform a wide range of activities in your Orbit workspace programmatically. The [API reference guide](https://docs.orbit.love/reference#about-the-orbit-api) is a good starting point for exploration. For our purposes, we will be using the [create a new activity for existing or new member](https://docs.orbit.love/reference#post_-workspace-id-activities) API operation.

[![API access included in every Orbit account](https://cdn.sanity.io/images/cad8jutx/production/7cde875a0add066f1634e2658172691efb214fa4-887x158.png)](https://app.orbit.love/signup)

> API access is included with every account! Try it out by [signing up today](https://app.orbit.love/signup).

### Creating a New Custom Activity

The [Orbit documentation](https://docs.orbit.love/reference#key-concepts) informs us that when we send a new activity to Orbit through the API, it will also either retrieve an existing member in our workspace or create a new member if an existing one cannot be found. This means we only need to send one HTTP request to Orbit to both create the blog post comment as an activity and attach it to a member!

According to the API reference we need to define an `activity_type` and a `title` for the activity, along with member `identity` information. We will also send more descriptive information to further supplement the record in the workspace, such as a `description` and a `link`.

### Constructing the Custom Activity Data Object

Let's first construct the request body that we will send in the HTTP request. We will create two methods first, `#sanitize_comment`and `#construct_commenter`. They both will clean the data we received from the DEV API and put it in the proper format for Orbit.

The `#sanitize_comment` method removes all the HTML tags from the comments to leave us with just the body of the message.

The `#construct_commenter` method forms a hash representing the identifying information of the commenter. If the DEV commenter has a Twitter or GitHub username in their DEV profile we add it to the information we send to Orbit.

```ruby
  def sanitize_comment(comment)
    comment = ActionView::Base.full_sanitizer.sanitize(comment)

    comment.gsub("\n", " ")
  end
  
  def construct_commenter(commenter)
    hash = {
      'name': commenter[:name],
      'username': commenter[:username]
    }

    unless commenter[:twitter_username].nil? || commenter[:twitter_username] == ""
      hash.merge!('twitter': commenter[:twitter_username])
    end

    unless commenter[:github_username].nil? || commenter[:github_username] == ""
      hash.merge!('github': commenter[:github_username])
    end

    hash
  end
  
  def construct_body
    @commenter = construct_commenter(@commenter)
    
    hash = {
      activity: {
        activity_type: "dev:comment",
        key: "dev-comment-#{@comment[:id]}",
        title: "Commented on the DEV blog post: #{@article_title}",
        description: sanitize_comment(@comment[:body_html]),
        occurred_at: @article[:created_at],
        link: @article[:url],
        member: {
          name: @commenter[:name],
          devto: @commenter[:username]
        }
      },
      identity: {
        source: "devto",
        username: @commenter[:username]
      }
    }

    hash[:activity][:member].merge!(twitter: @commenter[:twitter]) if @commenter[:twitter]

    hash[:activity][:member].merge!(github: @commenter[:github]) if @commenter[:github]

    hash
  end
```

In the `#construct_body` method we create a hash with all the data we plan to send to Orbit.

-   The `activity_type` is `dev:comment`
-   A custom ID in the `key` field interpolating the string dev-comment with the DEV comment ID
-   The `title` of Commented on the DEV blog post interpolated with the blog post title
-   The comment itself in the `description` field stripped of all of its HTML tags
-   The URL to the DEV blog post in the `link` field
-   The `member` and `identity` objects with the user's name and DEV username
-   If the commenter has a Twitter or GitHub username in their profile those are added to the HTTP request body as well in the `member` object

### Posting the Activity to Orbit

We are now ready to make the `POST` request to Orbit with our data. This will be a standard Ruby HTTP request using the `net/http` library:

```ruby
url = URI("https://app.orbit.love/api/v1/#{@workspace_id}/activities")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
req = Net::HTTP::Post.new(url)
req["Accept"] = "application/json"
req["Content-Type"] = "application/json"
req["Authorization"] = "Bearer #{@api_key}"

req.body = construct_body

req.body = req.body.to_json

response = http.request(req)

JSON.parse(response.body)
```

Once the activity has been sent to the Orbit API, you should see it soon after in your workspace!

![Screenshot of a DEV blog post comment on Orbit](https://cdn.sanity.io/images/cad8jutx/production/1328c3eb60dc1454edee4078b968e87079f65207-1420x206.png)

## Using the Ruby Gem

The code in this tutorial comes from a fully-featured Ruby gem that abstracts a lot of the work for you. It also includes a command-line interface (CLI) to make execution even more straightforward.

The code for the gem can be found on [GitHub](https://github.com/bencgreenberg/dev_orbit). To install the gem in your project add it to your `Gemfile`:

```ruby
gem 'dev_orbit'
```

Then, run `bundle install` from the command line. Once the gem has been included into your project, you can instantiate a client by passing in your relevant DEV and Orbit API credentials:

```ruby
client = DevOrbit::Client.new(
  orbit_api_key: '...',
  orbit_workspace: '...',
  dev_api_key: '...',
  dev_username: '...'
)
```

To fetch all new comments on your DEV blog posts within the past day, you can invoke the `#comments` instance method on your client:

```ruby
client.comments
```

This method will gather all the comments in the past day from DEV, format them for activities in your Orbit workspace, and make the `POST` request to the Orbit API to add them.

### Automating with GitHub Actions

What if you would like to run this gem once a day to fetch all your latest DEV comments and add them to your Orbit workspace? You could manually run it daily, or you can use [GitHub Actions](https://github.com/features/actions) to automate it for you!

GitHub Actions is an environment to run all your software workflows provided by GitHub for free for any public repository. You can use it to run your code's testing suite, to deploy to the cloud or any one of numerous use cases. In our example, we will use GitHub Actions to run this gem once a day on a [cron](https://crontab.guru/) schedule.

Inside your GitHub repository create a folder called `.github`, and another one called `workflows` inside the first one. Within the workflows folder create a YAML file called `dev_comments.yml`. Add the following YAML text into the file:

```yaml
name: Check For New DEV Blog Post Comments and Add to Orbit Workspace
on:
  schedule:
    - cron: "0 0 */1 * *"
  workflow_dispatch:
    branches:
      - main
jobs:
  comments-workflow:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
      with:
        fetch-depth: 0
        submodules: recursive
    - name: Set up Ruby 2.7.2
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: 2.7.2
    - name: Ruby gem cache
      uses: actions/cache@v1
      with:
        path: vendor/bundle
        key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
        restore-keys: |
          ${{ runner.os }}-gems-
    - name: Bundle Install
      run: |
        gem update --system 3.1.4 -N
        gem install --no-document bundler
        bundle config path vendor/bundle
        bundle install --jobs 4 --retry 3
    - name: Check for New Comments
      run: |
        bundle exec dev_orbit --check-comments
      env:
        DEV_API_KEY: ${{ secrets.DEV_API_KEY }}
        DEV_USERNAME: ${{ secrets.DEV_USERNAME }}
        ORBIT_API_KEY: ${{ secrets.ORBIT_API_KEY }}
        ORBIT_WORKSPACE_ID: ${{ secrets.ORBIT_WORKSPACE_ID }}
```

> This `YAML` workflow assumes that you have uploaded your `Gemfile` with the `dev_orbit` gem listed inside of it.

The above workflow creates a Ruby developer environment inside your GitHub Actions instance. It then installs the dependencies listed in your Gemfile, and finally, uses the gem's CLI to check for new blog post comments and add them to your Orbit workspace.

The only other task you need to do in order for this automation to work is to add your credentials for DEV and Orbit into your GitHub repository's secrets settings. You can find your secrets by navigating to "Settings" from within your repository and clicking on "Secrets" in the side navigation bar.

![Example of GitHub secrets settings page](https://cdn.sanity.io/images/cad8jutx/production/0e7e3faba19081a4fffd0ea60c57624b44b505c8-1015x745.png)

Once your secrets have been added, this workflow will automatically run once a day for you! You can simply go to your Orbit workspace and find the latest DEV blog comments in your member activities without needing to do anything else.

Want to learn more about using the Orbit API? Check out these other resources:

-   [How To Add Docs Feedback to Your Orbit Workspace with Ruby on Rails](https://orbit.love/blog/how-to-add-docs-feedback-to-your-orbit-workspace-with-ruby-on-rails/)
-   [Community-built Open Source Resources](https://docs.orbit.love/docs/community-built-resources)
-   [Orbit API Reference](https://docs.orbit.love/reference#about-the-orbit-api)