Slackened
Dependencies
- Setup a Slack Incoming Webhook
- Optionally setup Interactivity
- Store the URL as an ENV Variable outside the repo for safety
Getting started
-
Add
slackened
to yourGemfile
gem 'slackened'
-
Configure the Webhook URL in an initializer
Slackened.configure do |config| config.webhook_url = ENV.fetch('SLACK_WEBHOOK_URL') { puts 'SLACK_WEBHOOK_URL is missing.' } end
-
Build a layout
class PaymentFailedMessage < Slackened::Surface::Message def self.layout(payment_id:, context:) build do |message| message.row header('Payment failed!') message.row context(context) message.row section("Please do something about this: #{payment_id}") # NOTE: # if you want/need to design singular blocks via BlockKit builder # then use the `custom` method: message.row custom({ "type": "section", "text": { "type": "mrkdwn", "text": "Retry the batch process" }, "accessory": { "type": "button", "text": { "type": "plain_text", "text": "Retry", "emoji": true } } }) end end end
-
Supply the variables
class ExampleService def self.call # Calling .post WILL NOT raise an Error response = ExampleMessage.post( context: Rails.env, payment_id: 'payment-abc-erf-123' ) puts response.body # Calling .post! WILL raise an Error begin ExampleMessage.post!( context: Rails.env, payment_id: 'payment-abc-erf-123' ) rescue Slackened::Error puts "Fail!" end end end
Interactivity
-
Enable Interactivity & Shortcuts for your app
https://api.slack.com/apps/YOUR-APP-ID/interactive-messages
-
Set the
signing_secret
in an initializerSlackened.configure do |config| config.webhook_url = ENV.fetch('SLACK_WEBHOOK_URL') { puts 'SLACK_WEBHOOK_URL is missing.' } config.signing_secret = ENV.fetch('SLACK_SIGNING_SECRET') { puts 'SLACK_SIGNING_SECRET is missing.' } end
-
Validate that the request is real & handle the response
class ExampleController < ApplicationController before_action :validate_request def response # Handle the request # https://api.slack.com/interactivity/handling#message_responses payload = JSON.parse(params.fetch(:payload)) response_url = payload['response_url'] # See the Getting Started section above for setting up a Message # you can override the default URL via the `post` method here... ExampleResponseMessage.post( message: 'Message received!', user_id: payload.dig('user', 'id'), url: payload['response_url'] ) render plain: :ok end private def validate_request # https://api.slack.com/authentication/verifying-requests-from-slack authentic = Slackened::Authentication.validate_request( timestamp: request.headers.fetch('X-Slack-Request-Timestamp'), signature: request.headers.fetch('X-Slack-Signature'), body: request.raw_post ) render(plain: 'not ok', head: :unauthorized) and return unless authentic end end
Blocks
Usable components:
-
Actions
-
Button
button( plain_text: 'Click here', action_id: 'foo-1', value: 'foo-bar' )
-
Context
context("#{Rails.env} | 2024-12-30")
-
Custom
This is not a BlockKit component, it lets you pass in a single valid block via the BlockKit builder
custom({ "type": "section", "text": { "type": "mrkdwn", "text": "Retry the batch process" }, "accessory": { "type": "button", "text": { "type": "plain_text", "text": "Retry", "emoji": true } } })
-
Divider
divider
-
Header
header('Hello world!')
-
Section
section('Passing in a single string here creates a single column section')
section( 'Passing in multiple strings', 'will create a two column section', 'and you are allowed up to ten params', 'they must all be strings' )
-
Text
text('You may not need to use this directly, actually.')
Surfaces
- Message
Security
- Authenticate responses from Slack
TODO
- Better tests
- Add
Slackened::Surface::Modal
as per https://api.slack.com/interactivity/handling - More comprehensive support for all the Blocks
Development
-
Clone this repo
-
Install the libraries
bundle install