<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nuno Namorado</title>
    <description>The latest articles on DEV Community by Nuno Namorado (@nunonamorado).</description>
    <link>https://dev.to/nunonamorado</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F107139%2F83454279-dad3-436e-929a-70ecb9531b27.jpeg</url>
      <title>DEV Community: Nuno Namorado</title>
      <link>https://dev.to/nunonamorado</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nunonamorado"/>
    <language>en</language>
    <item>
      <title>Building a Slack App using Ruby and Sinatra</title>
      <dc:creator>Nuno Namorado</dc:creator>
      <pubDate>Mon, 11 Mar 2019 14:43:08 +0000</pubDate>
      <link>https://dev.to/runtime-revolution/building-a-slack-app-using-ruby-and-sinatra-2ie4</link>
      <guid>https://dev.to/runtime-revolution/building-a-slack-app-using-ruby-and-sinatra-2ie4</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2A10lZcKeJOYAjJbW9" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2A10lZcKeJOYAjJbW9"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@morrec?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Morre Christophe&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My team at Runtime Revolution uses an in-house app for team management and other day-to-day chores. Recently, I was asked to integrate &lt;a href="https://api.slack.com/slash-commands" rel="noopener noreferrer"&gt;&lt;em&gt;Slack’s Slash Commands&lt;/em&gt;&lt;/a&gt; into it.&lt;/p&gt;

&lt;p&gt;Being new to Ruby I accepted the challenge with added motivation and drive. This was a good side project to improve my Ruby skills.&lt;/p&gt;

&lt;p&gt;From the start, I wanted to create a small standalone app that could be easily integrated with our existing Rails application. There are a couple of web frameworks out there. Some offer Rails-like features, &lt;a href="http://hanamirb.org/" rel="noopener noreferrer"&gt;&lt;em&gt;Hanami&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; &lt;a href="http://padrinorb.com/" rel="noopener noreferrer"&gt;&lt;em&gt;Padrino&lt;/em&gt;&lt;/a&gt;, just to name a few. However, none offered the small footprint and modularity that &lt;a href="http://sinatrarb.com" rel="noopener noreferrer"&gt;&lt;em&gt;Sinatra&lt;/em&gt;&lt;/a&gt; implies. So I went with Sinatra.&lt;/p&gt;

&lt;p&gt;Providing a simple yet powerful DSL, Sinatra enables the creation of web applications with ease. Using community created modules we are able to quickly build a fully-fledged API server with authentication, logging, etc. or a small HTTP module for other Ruby applications or services.&lt;/p&gt;

&lt;p&gt;In this article, I will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;give a brief overview of &lt;em&gt;Slash Commands&lt;/em&gt; and &lt;em&gt;Actions&lt;/em&gt;, as well as the concept behind interactive messages;&lt;/li&gt;
&lt;li&gt;guide you through the creation and configuration of a Slack application;&lt;/li&gt;
&lt;li&gt;build a “Surf forecasting” Sinatra application for receiving and sending Slack messages;&lt;/li&gt;
&lt;li&gt;show how to deploy an app using Heroku service or embed it in a Rails application.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Slash Commands and Actions
&lt;/h3&gt;

&lt;p&gt;Slack apps can do more than just sending simple text messages. Using the &lt;em&gt;Slash Commands&lt;/em&gt; and &lt;em&gt;Interactive Components&lt;/em&gt; (buttons, menus, date pickers, popups, etc.), apps are able to effectively create more engaging experiences.&lt;/p&gt;

&lt;p&gt;The diagram below provides a basic outline of the typical flow using interactive messages. Note that the interactions can be triggered by a variety of sources found within the API provided by Slack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F512%2F1%2A7sqqRAtDN49QUDkuMlhQuA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F512%2F1%2A7sqqRAtDN49QUDkuMlhQuA.png"&gt;&lt;/a&gt;Slack interactions overview. Taken from &lt;a href="https://api.slack.com/messaging/interactivity" rel="noopener noreferrer"&gt;Slack docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the context of this article, the origin will be a user action triggered by a command_._ The app will then send an enriched message containing buttons, which allow the user to select one of several outcomes presented.&lt;/p&gt;

&lt;p&gt;Slack API documentation can be somewhat confusing when referring to actions because almost everything is an action. However, when it comes to configuring a Slack app, as we will see further along, there is a clear separation between &lt;em&gt;Slash Commands&lt;/em&gt; and &lt;em&gt;Interactive Components.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What are &lt;em&gt;Slash commands?&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Slash commands,&lt;/em&gt; as the name states, are commands that the user can execute by writing with a leading / followed by the name of the command. A known example of this is the /remind.&lt;/p&gt;

&lt;p&gt;Slack apps can register new Slash Commands, which will instruct Slack to send an HTTP POST request to the receiving server. The app server will act accordingly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The string &lt;em&gt;/&amp;lt;name&amp;gt;&lt;/em&gt; is what identifies the command and all words that follow will be the command parameters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What are &lt;em&gt;Actions?&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Actions are events triggered when the user selects &lt;a href="https://api.slack.com/actions" rel="noopener noreferrer"&gt;a menu action&lt;/a&gt; or clicks any interactive element on a message (buttons, selects, date pickers, etc.). Slack apps can register up to 5 actions in the &lt;em&gt;Interactive Components&lt;/em&gt; page or have unlimited actions if they use interactive elements on messages.&lt;/p&gt;

&lt;p&gt;Every action is identified by its respective &lt;em&gt;callback_id,&lt;/em&gt; and every time the user triggers one a different HTTP POST will be sent to the receiving server.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Creating and configuring a Slack Application
&lt;/h3&gt;

&lt;p&gt;There are a couple of things to consider when creating a Slack application for sending and receiving interactive messages. We will have to set specific auth permissions, activate the &lt;em&gt;Interactive Components&lt;/em&gt; feature, and configure &lt;em&gt;Slash Commands.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2.1. Create the app
&lt;/h4&gt;

&lt;p&gt;Navigate to &lt;a href="https://api.slack.com/apps" rel="noopener noreferrer"&gt;https://api.slack.com/apps&lt;/a&gt; and press the “&lt;em&gt;Create New App”&lt;/em&gt; button. Add a name and assign it to a workspace of your choice.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.2. Configuring Slash Commands
&lt;/h4&gt;

&lt;p&gt;Having created the app, go to &lt;em&gt;Slash Commands&lt;/em&gt; page and press “&lt;em&gt;Create New Command&lt;/em&gt;”. Fill the form. Set the &lt;em&gt;Request URL&lt;/em&gt; with a dummy URL, we’ll come back to this page later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F983%2F1%2AQioZF-Wdui3SVT8-9xgtvg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F983%2F1%2AQioZF-Wdui3SVT8-9xgtvg.png"&gt;&lt;/a&gt;Command form&lt;/p&gt;

&lt;h4&gt;
  
  
  2.3. Activating Interactive Components
&lt;/h4&gt;

&lt;p&gt;Go to the &lt;em&gt;Interactive Components&lt;/em&gt; page and switch “on” the feature. Again, set the &lt;em&gt;Request URL&lt;/em&gt; with a dummy URL. This will be updated later, with the actual endpoint. Hit “Save changes” on the bottom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F998%2F1%2AqSx3UUdWaXGmVDpEq4Kauw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F998%2F1%2AqSx3UUdWaXGmVDpEq4Kauw.png"&gt;&lt;/a&gt;Interactive components configuration&lt;/p&gt;

&lt;h4&gt;
  
  
  2.4. Set permissions
&lt;/h4&gt;

&lt;p&gt;Going to &lt;em&gt;OAuth &amp;amp; Permissions&lt;/em&gt; page_,_ in the Scopes section, search for “&lt;strong&gt;Add slash commands and add actions to messages (and view related content)&lt;/strong&gt;” and save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F705%2F1%2AnlQLIqqxS86GXp1KlhL_1A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F705%2F1%2AnlQLIqqxS86GXp1KlhL_1A.png"&gt;&lt;/a&gt;App permissions&lt;/p&gt;

&lt;h4&gt;
  
  
  2.5. Installing
&lt;/h4&gt;

&lt;p&gt;After following the previous steps, we are ready to install the app in the selected workspace. Go to the &lt;em&gt;Install App&lt;/em&gt; page and trigger the installation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Building the app
&lt;/h3&gt;

&lt;p&gt;We are going to build an application that will give us the current surf forecast for a given place in the world. We will use &lt;a href="https://www.windguru.cz/1060" rel="noopener noreferrer"&gt;Windguru’s website&lt;/a&gt; to compile the necessary information. For added fun, let’s also include the location map of the spot, so it’s easier to interpret the information given by the variables. We will use &lt;a href="https://docs.mapbox.com/api/maps/#static" rel="noopener noreferrer"&gt;Mapbox’s static maps API&lt;/a&gt; for that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;During the creation of this article and while coding the example app, I identified some common behaviours for proccessing and sending Slack messages. So, I decided to create a simple Sinatra module and provide it as a gem (&lt;a href="https://github.com/nunonamorado/sinatra-slack" rel="noopener noreferrer"&gt;sinatra-slack&lt;/a&gt;). All examples shown are using this gem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  3.1. Interactions
&lt;/h4&gt;

&lt;p&gt;The app will have two types of interactions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the user uses the command /surf today carcavelos for example, to retrieve the forecast information. If the provided variable, &lt;em&gt;spot_name&lt;/em&gt;, is enough to pinpoint the desired surf spot, the forecast is returned to the user.&lt;/li&gt;
&lt;li&gt;If during the first interaction, the search result is ambiguous, the app will send in return a message with multiple buttons one per each surf spot result, up to a limit of 5. This will allow the user to continue the flow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F835%2F1%2AANzly1NRuP5hOJxYHEvkhg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F835%2F1%2AANzly1NRuP5hOJxYHEvkhg.gif"&gt;&lt;/a&gt;Interaction 1&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F835%2F1%2A5azSmb5HsTcXeaMjF3d25A.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F835%2F1%2A5azSmb5HsTcXeaMjF3d25A.gif"&gt;&lt;/a&gt;Interaction 2&lt;/p&gt;

&lt;h4&gt;
  
  
  3.2. Requirements
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Ruby environment correctly configured;&lt;/li&gt;
&lt;li&gt;code from repo — &lt;a href="https://github.com/nunonamorado/slash_command_article" rel="noopener noreferrer"&gt;Slash Command Article&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;a working Slack App with a configured /surf command and Interactive Components activated.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com/download" rel="noopener noreferrer"&gt;ngrok tool&lt;/a&gt; to tunnel all Slack requests to your local dev environment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.mapbox.com/" rel="noopener noreferrer"&gt;Mapbox account&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3.3. Local development
&lt;/h4&gt;

&lt;p&gt;Slack needs to send requests to valid HTTP endpoints, so we will have to set up some HTTP forwarding using ngrok.&lt;/p&gt;

&lt;p&gt;Download the tool from their website, create a free account. When logged in, start the forwarding requests by running,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./ngrok http 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;this will start the server and you are now able to receive requests on your dev machine.&lt;/p&gt;

&lt;p&gt;Go back to Slack App’s configurations page, in the /surf command configuration paste the ngrok endpoint to the &lt;em&gt;Request URL&lt;/em&gt; input and do the same for the &lt;em&gt;Interactive Components&lt;/em&gt; section.&lt;/p&gt;

&lt;p&gt;The final URLs should look something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;https://&amp;lt;ngrok-domain&amp;gt;/slack/commands&lt;/li&gt;
&lt;li&gt;https://&amp;lt;ngrok-domain&amp;gt;/slack/actions&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  3.4. Starting the app
&lt;/h4&gt;

&lt;p&gt;Before starting the application, set the environment variables&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MAPBOX_API_TOKEN — create one in the &lt;a href="https://account.mapbox.com/" rel="noopener noreferrer"&gt;Mapbox’s account page&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;SLACK_SIGNING_SECRET — in the &lt;em&gt;Basic Information&lt;/em&gt; page, copy the secret from the &lt;em&gt;Credentials&lt;/em&gt; section.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;either using the .env file or the command line and start the app by running,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle exec rackup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To use .env, install &lt;a href="https://github.com/bkeepers/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt; gem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  3.5. Project overview
&lt;/h4&gt;

&lt;p&gt;The S_urforecaster_ app consists of the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app.rb — your main app file. This is where the Sinatra application will be configured;&lt;/li&gt;
&lt;li&gt;config.ru— this is the Rack configuration file;&lt;/li&gt;
&lt;li&gt;lib/surforecaster.rb — helper class to fetch data from Windguru’s API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;app.rb&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The code below contains comments for some relevant parts. However, a couple of things to notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The class must inherit from Sinatra::Base ;&lt;/li&gt;
&lt;li&gt;To use the Slack app specific DSL, register the Sinatra::Slack module;&lt;/li&gt;
&lt;li&gt;All requests from Slack need to be verified. By setting the :slack_secret option, the module will verify each request sent to both commands_endpoint and actions_endpoint. For more information about the Slack verification process, &lt;a href="https://api.slack.com/docs/verifying-requests-from-slack" rel="noopener noreferrer"&gt;see their docs&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;The quick_reply parameter in both command and action definitions lets you set the text that the server will send back to Slack, as soon as it receives the command or action request. This is not necessary, but it’s a good practice to let the user know that their request was correctly received and is being processed.&lt;/li&gt;
&lt;li&gt;Under the hood, the module is using Sinatra::Async to process the requests asynchronously. Slack requires that all command and action requests be answered within a 3-second interval, so we need a mechanism to process the request in the background for longer tasks. We will then have to respond with HTTP Post, to the response_url sent in the original request.&lt;/li&gt;
&lt;li&gt;Command and Action signature definitions use the Mustermann string matching definitions. Looking at the &lt;em&gt;command&lt;/em&gt; signature definition /surf *granularity :spot_name, the &lt;strong&gt;*&lt;/strong&gt; allows catching the first word in a non-greedy way, leaving the rest of the words for the &lt;em&gt;spot_name&lt;/em&gt; variable. To know more about it, &lt;a href="https://github.com/sinatra/mustermann/blob/master/mustermann/README.md#-sinatra-pattern" rel="noopener noreferrer"&gt;go here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;config.ru&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will use the rackup command to start the Sinatra application. The config.ru file contains all the necessary options for the app to run. Notice the topmost comment, this is where you can set all command-line options which rackupwill pick up.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;lib/surforecaster.rb&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is just a basic ruby class for fetching forecast information. It contains 3 methods that will be used in different stages of the command and action flows.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  3.6. Adding interactivity to messages
&lt;/h4&gt;

&lt;p&gt;As described above, Slack responses can be simple text messages or more complex, with rich text, images and other actionable elements like buttons and menus.&lt;/p&gt;

&lt;p&gt;For &lt;em&gt;Surforecaster&lt;/em&gt; app, we will need to send both messages with images and buttons.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To send messages with interactive components, two message properties are required — &lt;em&gt;callback_id&lt;/em&gt; and &lt;em&gt;fallback&lt;/em&gt;. In the example below, we are using a helper method to build a slack message and pass along the &lt;em&gt;callback_id&lt;/em&gt; value. If you look closely, we are setting the same name as the action signature defined in the app.rb, using the string interpolation to set the &lt;em&gt;callback_id&lt;/em&gt; according to the current command &lt;em&gt;granularity&lt;/em&gt; (that was sent by the command)&lt;em&gt;.&lt;/em&gt; This is a nice way of passing around values between Slack and the app, without having to cache it somewhere else.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;To send messages with images, you just have to set the property &lt;em&gt;image_url&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  4. Deploying
&lt;/h3&gt;

&lt;p&gt;The final step of this exercise is deploying the app we just built. As previously stated, Sinatra apps can be deployed as a standalone app or embeded in a Rails application.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.1. Standalone mode
&lt;/h4&gt;

&lt;p&gt;We will be deploying &lt;em&gt;Surforecaster&lt;/em&gt; using &lt;a href="https://www.heroku.com" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt; and &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are a couple of things you need to do first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://signup.heroku.com" rel="noopener noreferrer"&gt;create an account on Heroku&lt;/a&gt; or use an existing one;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devcenter.heroku.com/articles/heroku-cli#download-and-install" rel="noopener noreferrer"&gt;download and install Heroku CLI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a new app in Heroku using,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heroku create \&amp;lt;app-name\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, we need to set your app stack to container. Run the command,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heroku stack:set container -a \&amp;lt;app-name\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Set the values for the two environment variables (SLACK_SIGNING_SECRET and MAPBOX_API_TOKEN) either in the app settings page, c_onfig vars_ section or using Heroku CLI with,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heroku config:set SLACK\_SIGNING\_SECRET -a \&amp;lt;app-name\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, let’s look at these 2 files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;heroku.yml — this is the manifest file with the definition of the Heroku app;&lt;/li&gt;
&lt;li&gt;Dockerfile — contains the instructions for building the app image that will be deployed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;heroku.yml&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build.docker.web tells Heroku to build the Dockerfile at the root of the project;&lt;/li&gt;
&lt;li&gt;run.web command is executed when launching the container. Heroku doesn’t let us define a static port number, so we have to set it through an environment variable, $PORT.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inherits from an official Ruby image;&lt;/li&gt;
&lt;li&gt;installs necessary dependencies missing from the image;&lt;/li&gt;
&lt;li&gt;copies the app files to the working directory.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will be using the &lt;a href="https://devcenter.heroku.com/articles/github-integration" rel="noopener noreferrer"&gt;Github-Heroku integration&lt;/a&gt; for automatic deployments, so that every time a code change is pushed, Heroku will build and deploy the application. However, you could also choose to deploy using &lt;a href="https://devcenter.heroku.com/articles/git" rel="noopener noreferrer"&gt;Heroku Git&lt;/a&gt; or &lt;a href="https://devcenter.heroku.com/articles/container-registry-and-runtime" rel="noopener noreferrer"&gt;Container Registry&lt;/a&gt; methods.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.2. Embedding in a Rails App
&lt;/h4&gt;

&lt;p&gt;Another way of deploying this app is to embed it in an existing Rails app. You can do this in two ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing the config.ru file to something like this:&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;or by using Rails routes:&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Last step
&lt;/h3&gt;

&lt;p&gt;After the deployment is complete, copy&amp;amp;paste the new URL to the Slack app configuration pages and that’s it! Go to the Slack workplace and start “commanding” stuff.&lt;/p&gt;

&lt;h3&gt;
  
  
  Future work
&lt;/h3&gt;

&lt;p&gt;By creating Slack Apps with Interactive Components and Slash Commands we can accomplish really useful integrations that can simplify any company’s processes.&lt;/p&gt;

&lt;p&gt;Keep in mind that we’ve barely scratched the surface in terms of interactive elements, we can still experiment further with select menus, date pickers, popups, confirmation messages, etc.&lt;/p&gt;

&lt;p&gt;During the making of this article, I created a Sinatra module accessible through the &lt;a href="https://rubygems.org/gems/sinatra-slack" rel="noopener noreferrer"&gt;“sinatra-slack” gem&lt;/a&gt;. It’s still not production ready and there are a lot of interactive component helpers missing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I work at&lt;/em&gt; &lt;a href="http://www.runtime-revolution.com/" rel="noopener noreferrer"&gt;&lt;em&gt;Runtime Revolution&lt;/em&gt;&lt;/a&gt; &lt;em&gt;as a Full-stack developer currently focusing on Ruby. My background is .Net and C#, with incursions into Angular and React.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>sinatra</category>
      <category>slack</category>
      <category>heroku</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
