telegram-bot Ruby Toolkit

repository·master·Indexed 20 days ago

https://github.com/telegram-bot-rb/telegram-bot

A Ruby toolkit for developing Telegram bots featuring a lightweight thread-safe API client, a command-based UpdatesController, and specialized support for Rails and standalone applications. It provides tools for both poller-mode (development) and webhook-mode (production), session management via ActiveSupport::Cache, multi-step interaction handling with MessageContext, and an async mode for offloading requests to queue adapters.

Tokens
8.5K
Snippets
35
Records
45
Agent score
62%

What's inside telegram-bot

  1. Overview of Telegram::Bot features

    master

    The telegram-bot package provides a suite of tools for building Telegram bots, optimized for both Rails and standalone Ruby applications.

    Core Components

    • Lightweight Client: A thread-safe client for the Telegram Bot API using httpclient.
    • Controller: A message parser that allows you to define methods for commands instead of using complex case statements.
    • Middleware & Routes: Helpers designed for production environments (typically webhook-mode).
    • Poller: A tool for development environments that includes an automatic source-reloader.
    • Rake Tasks: Utilities to manage and update webhook URLs.
    • Async Mode: Support for offloading work to a queue adapter to handle network errors gracefully.

    Deployment Modes

    • Development: Use poller-mode for local development.
    • Production: Use webhook-mode for production environments, though poller-mode is also supported.
  2. Enable Async mode for requests

    master

    To process updates quickly without waiting for Telegram API responses, you can enable async mode. This serializes the request and pushes it to a queue (like ActiveJob in Rails).

    Configuration

    Add async: true to your bot's configuration.

    Limitations

    • The client will not return the API response to the caller.
    • Sending files is not supported in async mode because file objects cannot be serialized into a queue.

    Usage

    You can wrap specific calls to disable async mode temporarily: bot.async(false) { bot.send_photo(...) }.

    # In config
    Telegram.bots_config = {
      default: { token: 'TOKEN', async: true }
    }
    
    # To bypass async for a specific call
    bot.async(false) { bot.send_photo(chat_id: 123, photo: File.open('img.jpg')) }
  3. Manage sessions in UpdatesController

    master

    To maintain state between updates, include the Telegram::Bot::UpdatesController::Session module (or use the use_session! shortcut). Sessions use an ActiveSupport::Cache store.

    Configuration

    Set the store globally or per controller:

    # Globally
    Telegram::Bot::UpdatesController.session_store = :redis_store, {expires_in: 1.month}
    
    # Per controller
    MyController.session_store = :file_store

    Customizing Session Keys

    The default session ID is derived from the bot's username and (from || chat)['id']. To change this (e.g., to make a session unique to a specific user in a specific chat), override session_key.

    class Telegram::WebhookController < Telegram::Bot::UpdatesController
      use_session!
    
      def write!(text = nil, *)
        session[:text] = text
      end
    
      def read!(*)
        respond_with :message, text: session[:text]
      end
    
      private
    
      # Custom key: session persists per user per chat
      def session_key
        "#{bot.username}:#{chat['id']}:#{from['id']}" if chat && from
      end
    end
  4. Implement a Telegram::Bot::UpdatesController

    master

    The UpdatesController allows you to organize bot logic into readable methods based on the type of update received (e.g., message, callback_query, inline_query). A new instance is created for every update, ensuring isolation.

    Handling Update Types

    Define methods with the same name as the update type. For common updates, parameters are passed directly. For others, use the payload method to access the full object.

    Handling Commands

    Define public methods ending with ! to handle commands. Arguments are parsed from the message and passed to the method. Use splat arguments (*args) to prevent errors if users provide unexpected argument counts.

    Reply Helpers

    Use these helpers within your controller to respond easily using the context of the current update:

    • respond_with(type, params): Sets chat_id from the update.
    • reply_with(type, params): Sets chat_id and reply_to_message_id.
    • answer_inline_query(results, params = {})
    • answer_callback_query(text, params = {})
    • edit_message(type, params = {})
    class Telegram::WebhookController < Telegram::Bot::UpdatesController
      # Handle a standard message
      def message(message)
        # logic here
      end
    
      # Handle a command like /start
      def start!(word = nil, *other_words)
        response = from ? "Hello #{from['username']}!" : 'Hi there!'
        respond_with :message, text: response
      end
    end
  5. Use MessageContext for multi-step interactions

    master

    The MessageContext module helps manage multi-step interactions (like a conversation flow). You can save a context state and define a handler for the next message that matches that state.

    1. Use save_context :context_name to set the state.
    2. Define a method named context_name to handle the incoming update.
    3. Use update_name within the handler to pass parsed data to your logic.
    class Telegram::WebhookController < Telegram::Bot::UpdatesController
      include Telegram::Bot::UpdatesController::MessageContext
    
      def rename!(*)
        save_context :rename_from_message
        respond_with :message, text: 'What name do you like?'
      end
    
      # This handles the next message after 'rename!' is called
      def rename_from_message(new_name)
        # logic to update name
        respond_with :message, text: 'Renamed!'
      end
    end
  6. Define Webhook Routes in Rails

    master

    The telegram_webhook helper simplifies defining webhook endpoints in Rails. It automatically creates routes at telegram/#{hash_of(bot.token)} and connects them to your controller.

    • Single bot: telegram_webhook TelegramController (defaults to :default bot).
    • Multiple bots: telegram_webhook TelegramChatController, :chat (uses the :chat key from Telegram.bots).
    • Custom route name: telegram_webhook TelegramController, as: :custom_name.
    # In routes.rb
    # For the default bot
    telegram_webhook TelegramController
    
    # For a specific bot named :chat
    telegram_webhook TelegramChatController, :chat
    
    # With a custom route name
    telegram_webhook TelegramController, as: :my_custom_webhook
  7. Configure Telegram bots in a Rails app

    master

    In a Rails application, Telegram.bots_config is automatically populated from the telegram section of your secrets.yml (or credentials for Rails >= 5.2).

    Single Bot Configuration

    development:
      telegram:
        bot: TOKEN
        # OR
        bot:
          token: TOKEN
          username: SomeBot

    Multiple Bots Configuration

    Use a bots key containing a hash of internal_bot_id => settings:

    development:
      telegram:
        bots:
          chat: TOKEN_1
          auction:
            token: TOKEN_2
            username: ChatBot

    Note for Rails >= 5.2: The library searches credentials first, then secrets. For Rails >= 6.0, ensure you run rails credentials:edit --environment development to configure bots in specific environments.

    development:
      telegram:
        bot: TOKEN
        # or
        bot:
          token: TOKEN
          username: SomeBot
    
        bots:
          chat: TOKEN_1
          auction:
            token: TOKEN_2
            username: ChatBot
  8. Install the telegram-bot gem

    master

    To use this library, add it to your application's Gemfile or install it directly via the command line.

    Add the gem to your Gemfile:

    gem 'telegram-bot'

    Then run:

    bundle

    Manual Installation

    Install the gem directly using:

    gem install telegram-bot
  9. Run a Telegram Bot Poller

    master

    If you are not using webhooks, you can use a poller to fetch updates.

    In a Rails app

    Use the provided Rake task: bundle exec rake telegram:bot:poller

    You can specify which bot to poll using the BOT environment variable: BOT=chat bundle exec rake telegram:bot:poller.

    In any Ruby app

    Use Telegram::Bot::UpdatesPoller.start(bot, controller_class).

    # In Rails
    BOT=chat bundle exec rake telegram:bot:poller
    
    # In non-Rails
    Telegram::Bot::UpdatesPoller.start(bot, MyController)
  10. Test Telegram bots with ClientStub

    master

    For testing, use Telegram::Bot::ClientStub to prevent actual API calls. It stores requests in a requests hash for inspection.

    Setup

    Call Telegram::Bot::ClientStub.stub_all! before initializing any clients in your test environment.

    Integration Testing

    Depending on your environment, require the appropriate integration helper and tag your RSpec group:

    • :rails: For Rails apps (requires rspec-rails).
    • :rack: For non-Rails apps (requires rack-test).
    • :poller: Calls .dispatch directly.

    Example tag: RSpec.describe MyController, telegram_bot: :rails do ... end.

    # spec/environments/test.rb
    Telegram.reset_bots
    Telegram::Bot::ClientStub.stub_all!
    
    # spec/requests/telegram_webhooks_spec.rb
    require 'telegram/bot/rspec/integration/rails'
    
    RSpec.describe TelegramWebhooksController, telegram_bot: :rails do
      it 'shows usage of basic matchers' do
        # Verifies a sendMessage request was made
        expect { dispatch_command(:start) }.to make_telegram_request(bot, :sendMessage)
          .with(hash_including(text: 'msg text'))
      end
    end