How to Add DEV Comments to Your Orbit Workspace With Ruby
A step by step guide to bringing DEV blog post comments into your Orbit workspace with the Orbit API and Ruby
Ben Greenberg
April 27, 2021
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.
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.
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 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 account. Once you have your DEV account, you can generate an API Key in your Account Settings.
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, 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:
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
. 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:
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:
def filter_comments(comments)
comments.select do |comment|
comment["created_at"] <= 1.day.ago
end
end
Note: The1.day.ago
functionality in the code snippet above comes from ActiveSupport. To take advantage of it you need to addrequire "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 is a good starting point for exploration. For our purposes, we will be using the create a new activity for existing or new member API operation.
API access is included with every account! Try it out by signing up today.
Creating a New Custom Activity
The Orbit documentation 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.
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
isdev: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
andidentity
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:
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!
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. To install the gem in your project add it to your Gemfile
:
# Gemfile
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:
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:
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 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 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:
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 }}
ThisYAML
workflow assumes that you have uploaded yourGemfile
with thedev_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.
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:
You might also like:
- Why Orbit is Better Than Funnel for Developer Relations
- DevRel teams need tools and models created specifically for our discipline, and not just those adopted from other fields.
- Slack vs Discord vs Discourse: The best tool for your community
- An in-depth comparison of 3 top community platforms across dozens of factors.
- How we use Orbit to build Orbit
- A guide to how we use our product to build our community.