+2

Sending data to Slack channel from your app

This is the part two of our ongoing series on creating a complete Slack app and connecting with our rails app.

  • Module#1 Introduction
  • Module#2 Slack Web Hooks (sending data from your project to Slack)
  • Module#3 API creation, Slash commands (sending data from Slack to your project)
  • Module#4 Slack custom forms (sending data from Slack to your project interactive way)
  • Module#5 Creating Slack Bot (posting message to Slack as a bot user)
  • Module#6 Handling installation of your custom app to user's Slack Channel
  • Module#7 Releasing yout app in Slack Store

Creating a slack app

Go to api.slack.com and create a slack app for yourself.

After you're done, you'll be greeted with the control panel of the app.

Now we need to enable the WebHook feature for the app.

when you try to enable it, you'll be asked to select which workspace your app is connecting with.

Now, we are done configuring from Slack side. Simple as that.

You'll be given the post url where you'll send your api call. Just send a post message on the url on this structure {text: "your message"} and you'll get the message posted on Slack.

Creating the todo app

Just a basic todo app, which sits behind devise authentication. Enabling devise authentication should be easy enough for you guys to google, so I'm skipping that part. Now, lets create a Task model using the scaffold command.

rails g scaffold Task title start:datetime end:datetime done:boolean

We will modify the TasksControllerto call on the webhook whenever we do any action.

So, lets create a class ExternalApiCaller to post on the SlackWebhook for us.

require "net/http"
require "uri"
require "json"

class ExternalApiCaller
  def call uri, data
    uri = URI.parse uri

    request = Net::HTTP::Post.new(uri)

    req_options = { use_ssl: uri.scheme == "https" }
    request.content_type = "application/json"
    request.body = JSON.dump(data)

    response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
      http.request(request)
    end

    return response.body
  end
end

Here's a demo of it in action.

Now we modify our controller to fire this method whenever CRUD actions were done.

require "./app/services/external_api_caller"

class TasksController < ApplicationController
  before_action :authenticate_user!
  before_action :set_task, only: [:show, :edit, :update, :destroy]

  URI = "https://hooks.slack.com/services/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"

  # GET /tasks
  # GET /tasks.json
  def index
    @tasks = Task.all
  end

  # GET /tasks/1
  # GET /tasks/1.json
  def show
  end

  # GET /tasks/new
  def new
    @task = Task.new
  end

  # GET /tasks/1/edit
  def edit
  end

  # POST /tasks
  # POST /tasks.json
  def create
    @task = Task.new(task_params)

    respond_to do |format|
      if @task.save
        format.html { redirect_to @task, notice: 'Task was successfully created.' }
        format.json { render :show, status: :created, location: @task }

        send_slack_notification(
          ["#{current_user} created a new task: `#{@task.title}`",
           "\n", "#{@task.get_url}"].join)
      else
        format.html { render :new }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /tasks/1
  # PATCH/PUT /tasks/1.json
  def update
    respond_to do |format|
      if @task.update(task_params)
        format.html { redirect_to @task, notice: 'Task was successfully updated.' }
        format.json { render :show, status: :ok, location: @task }

        send_slack_notification(
          ["#{current_user} has updated task: `#{@task.title}`",
           "\n", "#{@task.get_url}"].join)
      else
        format.html { render :edit }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /tasks/1
  # DELETE /tasks/1.json
  def destroy
    title = @task.title
    @task.destroy
    respond_to do |format|
      format.html { redirect_to tasks_url, notice: 'Task was successfully destroyed.' }
      format.json { head :no_content }
    end

    send_slack_notification("#{current_user} has removed the task:`#{title}`")
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_task
      @task = Task.find(params[:id])
    end

    def send_slack_notification message
      return unless message.present?
      eac = ExternalApiCaller.new
      eac.call URI, {text: message}
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def task_params
      params.require(:task).permit(:title, :description, :start, :end, :done)
    end
end

And we're done !

Here's the workspace for the app c9.io/salekin.slack_webhook.

and here's the git repo.

Finishing thoughts

We could improve upon the app with adding Activity gem and call our ExternalApiCaller on each activity

Reference Material

Slack Documentation


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí