Stay Ahead in Ruby!
From development processes to the most useful gems, get it all straight in your inbox. Join our Ruby blog today!

Skip to main content

How to create Telegram Bot with Ruby

How to create Telegram Bot with Ruby - cover image

Intro #

Would you like to automate customer support for your business? Or perhaps you’d like to receive notifications from a 3rd party service that lacks such feature? Then you are in luck because you can build a Telegram bot! Telegram allows you to create customizable chatbots for different purposes.

Pros & Cons of Telegram bot:

Pros

  • Free. You can create a bot in Telegram at no cost since there are no subscription models or plans.
  • Flexible. Telegram is highly flexible because it offers a wide range of features, such as Inline mode for integrating bots into chats or groups, various button types for creating custom menus, the ability to handle user-provided media, the option to create and manage questionnaires, and a built-in payment system that enables easy payments, among other features.
  • Quickly. Using Telegram for your needs will be quick and convenient, as you will not need to create a separate interface. Everything will occur seamlessly within the Telegram platform itself.

Cons

  • Limitations. The bot’s usability is constrained by its exclusive availability on Telegram, which limits its integration with webpages or other software interfaces.
  • Heavily expandable. When a Telegram bot contains an abundance of complex and intertwined logic, attempting to expand its functionality can become a formidable task due to the potential for unintended consequences, difficult debugging, and the possibility of introducing new errors into the existing codebase.

This article will describe the detailed process of creating a Telegram bot using Ruby. Let’s dive into it!

Telegram Bot registration #

Before we can use the Telegram bot API, we need to register this bot in Telegram itself by using an official Telegram bot FatherBot. You need to do the following things:

  1. Write in the chat /newbot (you can select this command from the Telegram menu).

Start command example
2. Give your bot a name.

Start command example
3. Give your bot a nickname.

Start command example
4. That’s it! The bot has been created. You can copy his token (most importantly, do not show this token to anyone).

Start command example

Bot development #

Let’s create a bot that will respond to commands, and integrate a markup-based menu for improved user interaction.

The tool that will help us create our ruby bot is the telegram-bot-ruby gem.

Add it to your Gemfile and run bundle install.

# Gemfile

gem 'telegram-bot-ruby'

Now, we should create the telegram_bot_listener.rb file that will serve as codebase for our bot.

Why telegram_bot_listener? The bot can work in two modes of receiving updates. The first mode is the getUpdate method, and the second method is to get updates via webhooks. For this tutorial, I will use the getUpdate method.

First, we should import the bot’s methods into our telegram_bot_listener.rb.

require 'telegram/bot'

Now, let’s create a TelegramBotListener class with an initialize method that will use the API key that we’ve copied earlier and prepare our bot for further usage.

def initialize
    token = "6275464708:AAEIN6tmLtWkKcnXihkqcF0HYKN5kM0jm0o"
    @bot = Telegram::Bot::Client.new(token)
end

To start the bot and make it listen to the commands of our users, we should create a method that will process all the incoming messages.

def run_telegram_bot
    @bot.run do |bot|
        bot.listen do |message|

        end
    end
end

We’ve completed our basic setup and can finally dive into command processing and writing custom logic.

Bot response to commands #

When a user starts a bot for the first time, the /start command is automatically sent in the chat with the bot. Think of it as a registration command that will activate our bot.

We should write a handler logic for this command. Since the /start command is just a text message from the user, our bot will receive an object with a text property that contains the user’s message. If the text property contains the /start command, the bot will perform an action that we assigned to this command.

def run_telegram_bot
    @bot.run do |bot|
        bot.listen do |message|
            case message
            when Telegram::Bot::Types::Message
                case message.text
                when "/start"
                    user_full_name = "#{message.from.first_name} #{message.from.last_name}"
                    @bot.api.send_message(chat_id: message.from.id, text: "Hello #{user_full_name} 👋")
                end
            end
        end
    end
end

Now we can start the bot by calling the run_telegram_bot method and trigger it by sending the /start command in chat.

Start command example

You can also create additional commands for the bot by following the same process we did earlier.

Using markups to create menus #

There are 2 types of interactive buttons in Telegram, or rather 2 types of button markup - ReplyKeyboardMarkup and InlineKeyboardMarkup. The ReplyKeyboardMarkup is always below the chat, while the InlineKeyboardMarkup markup is attached to a specific message and moves around the chat always with it.

ReplyKeyboardMarkup #

First, let’s create an array that will contain basic information about each button.

reply_buttons = [[{text: "Say Hi"}], [{text: "Say Bye"}]]

You can see additional button options in the Telegram bot API documentation.

Now let’s create the markup object that will contain an array of parameters we assigned earlier. To enhance user-friendliness, I added a resize_keyboard: true parameter, as Telegram’s default setting generates large buttons on phones, which can make the application less user-friendly.

reply_button_markup = Telegram::Bot::Types::ReplyKeyboardMarkup.new(keyboard: reply_buttons,resize_keyboard: true)

To view the recently created markup, you must send a message that contains the parameters of the newly created markup.

@bot.api.send_message(chat_id: message.from.id, text: "Here are your reply buttons", reply_markup: reply_button_markup)

Let’s add a new command handler /generate_reply to make sure our bot can identify and display our buttons.

As a result, we got this:

when "/generate_reply"
    reply_buttons = [[{text: "Say Hi"}], [{text: "Say Bye"}]]
    reply_buttons_markup = Telegram::Bot::Types::ReplyKeyboardMarkup.new(keyboard: reply_buttons, resize_keyboard: true)
    @bot.api.send_message(chat_id: message.from.id, text: "Here are your reply buttons", reply_markup: reply_buttons_markup)
end
Creating Reply Markup

InlineKeyboardMarkup #

The process of creating these buttons is similar to the process of creating Reply buttons.

First, we create an array with the buttons we need. For this tutorial, the first button will redirect the user to Youtube, and the second button will be used as a callback.

inline_buttons = [[Telegram::Bot::Types::InlineKeyboardButton.new(text: "Youtube Link", url: "https://www.youtube.com/")],
Telegram::Bot::Types::InlineKeyboardButton.new(text: "Link with callback", callback_data: "I am callback data")]

Let’s create the markup for these buttons.

inline_buttons_markup = Telegram::Bot::Types::InlineKeyboardMarkup.new(inline_keyboard: inline_buttons, resize_keyboard: true)

Now, let’s send a message that uses the current markup to the chat.

@bot.api.send_message(chat_id: message.from.id, text: "Here are your inline buttons", reply_markup: inline_buttons_markup)

As a result, we got this:

when "/generate_inline"
    inline_buttons = [[Telegram::Bot::Types::InlineKeyboardButton.new(text: "Youtube Link", url: "https://www.youtube.com/")],
    Telegram::Bot::Types::InlineKeyboardButton.new(text: "Link with callback", callback_data: "I am callback data")]
    inline_buttons_markup = Telegram::Bot::Types::InlineKeyboardMarkup.new(inline_keyboard: inline_buttons, resize_keyboard: true)
    @bot.api.send_message(chat_id: message.from.id, text: "Here are your inline buttons", reply_markup: inline_buttons_markup)
end
Creating Reply Markup
It is considered a good practice to call the answerCallbackQuery method every time the user clicks on the inline button since it will notify the user that their request has been accepted by the bot and has either been submitted or is being processed.

Summary #

As a result, we got the following code, which responds to commands and creates different types of markups.

when Telegram::Bot::Types::Message
    case message.text
    when "/start"
        user_full_name = "#{message.from.first_name} #{message.from.last_name}"
        @bot.api.send_message(chat_id: message.from.id, text: "Hello #{user_full_name} 👋")
    when "/generate_reply"
        reply_buttons = [[{text: "Say Hi"}], [{text: "Say Bye"}]]
        reply_buttons_markup = Telegram::Bot::Types::ReplyKeyboardMarkup.new(keyboard: reply_buttons, resize_keyboard: true)
        @bot.api.send_message(chat_id: message.from.id, text: "Here are your reply buttons", reply_markup: reply_buttons_markup)
    when "/generate_inline"
        inline_buttons = [[Telegram::Bot::Types::InlineKeyboardButton.new(text: "Youtube Link", url: "https://www.youtube.com/")],
        Telegram::Bot::Types::InlineKeyboardButton.new(text: "Link with callback", callback_data: "I am callback data")]
        inline_buttons_markup = Telegram::Bot::Types::InlineKeyboardMarkup.new(inline_keyboard: inline_buttons, resize_keyboard: true)
        @bot.api.send_message(chat_id: message.from.id, text: "Here are your inline buttons", reply_markup: inline_buttons_markup)
    end
end

Generally speaking, the functionality I have explained above is sufficient to create a basic Telegram bot. However, it is important to keep in mind that Telegram offers many other features such as built-in payment options, group or chat management, and poll creation and management, which can greatly enhance the functionality of your bot.

Improvement #

Currently, all of the bot’s logic is stored in one file. In order to make the bot more readable and comprehensible, I have extracted the processing of each command into a separate method.

Our code handles three different commands directly written in the bot file. However, all these handlers can be placed into separate methods to enhance the readability of the bot’s code. To achieve this, you can create another file, such as commands_handler.rb, containing a CommandsHandler class. This class will be responsible for processing the commands.

# commands_handler.rb

class CommandsHandler
  def initialize(bot)
    @bot = bot
  end

  def start(message)
    # implementation of the 'start' command
    user_full_name = "#{message.from.first_name} #{message.from.last_name}"
    @bot.api.send_message(chat_id: message.from.id, text: "Hello #{user_full_name} 👋")
  end

  def send_reply_markup(message)
    # implementation of sending a message with reply markup
    reply_buttons = [[{text: "Say Hi"}], [{text: "Say Bye"}]]
    reply_buttons_markup = Telegram::Bot::Types::ReplyKeyboardMarkup.new(keyboard: reply_buttons, resize_keyboard: true)
    @bot.api.send_message(chat_id: message.from.id, text: "Here are your reply buttons", reply_markup: reply_buttons_markup)
  end

  def send_inline_markup(message)
    # implementation of sending a message with inline markup
    inline_buttons = [[Telegram::Bot::Types::InlineKeyboardButton.new(text: "Youtube Link", url: "https://www.youtube.com/")],
    Telegram::Bot::Types::InlineKeyboardButton.new(text: "Link with callback", callback_data: "I am callback data")]
    inline_buttons_markup = Telegram::Bot::Types::InlineKeyboardMarkup.new(inline_keyboard: inline_buttons, resize_keyboard: true)
    @bot.api.send_message(chat_id: message.from.id, text: "Here are your inline buttons", reply_markup: inline_buttons_markup)
  end
end

The telegram_bot_listener.rb file code will look like this:

# telegram_bot_listener.rb

require 'telegram/bot'
require_relative 'commands_handler'

class TelegramBotListener
    def initialize
        token = "6275464708:AAEIN6tmLtWkKcnXihkqcF0HYKN5kM0jm0o"
        @bot = Telegram::Bot::Client.new(token)
        commands_handler = CommandsHandler.new(@bot)
    end

    def run_telegram_bot
        @bot.run do |bot|
            bot.listen do |message|
                case message
                when Telegram::Bot::Types::Message
                    case message.text
                    when "/start"
                        commands_handler.start(message)
                    when "/generate_reply"
                        commands_handler.send_reply_markup(message)
                    when "/generate_inline"
                        commands_handler.send_inline_markup(message)
                    end
                end
            end
        end
    end
end

TelegramBotListener.new.run_telegram_bot

We are ready to provide expert's help with your product
or build a new one from scratch for you!

Contact MobiDev’s tech experts!