Rubyroid Labs
Tech Tips and Freebies

Full Guide on Creating Telegram Bot that Stores State

Full Guide on Creating Telegram Bot that Stores State

Reading Time: 6 minutes

Telegram bots are becoming the next big thing. With Pavel Durov’s promise to give away $1 million to the best Telegram bot developers, even those who were not very much interested in this topic, got some appetite. Luckily, among Rubyroid Labs Team we also have some developers interested in this topic.

We have asked our Team member Maxim Abramchuk to shade some light and make a guide on how to create a Telegram Bot that stores state. You could have already seen Maxim’s article about code style.

Let’s have a look at Maxim decided to share with us. As he says, he has a couple of reasons to write this article.

  1. At first, he has a repository called ruby-telegram-bot-starter-kit, which contains a boilerplate for creating simple Telegram bots. It’s pretty cool, it allows you to save data to database, translate your messages via i18n, use custom keyboards and etc., but as he realised later he did miss a couple of things that are pretty important.
    He has been asked a lot via Github issues about the right/possible way to store state of a Telegram bot vs user communication.
  2. The technic of communicating with user he has used in this repo was a plain old long-polling, which sucks, because actually Telegram has Webhook API which is a much more convenient way to setup user vs bot communication.

So, today we are going to write a little quest game bot in Telegram using Ruby on Rails, Webhook API and some architecture which will help you to store your user-bot state like a charm. Let’s imagine that you already have a Rails app created and Rails server started on localhost:3000.

Webhooks API is working with HTTPS resources only, so we need to use ngrok to proxy our localhost:3000 with some server accessible via HTTPS. So, let’s download ngrok (or install it via brew on OS X) and do a:

if everything is going ok you’ll see something like this
telegram

so, since we need an https, we will use this one

telegram

Our next step is to create a bot in Telegram and get it’s token
To do that you need to find a Botfather in Telegram.

telegram

Write him /newbot to start new bot creation.

telegram

Cool, now we have a rails server running and a Telegram bot available to communicate with our users.

Our next step is to setup a communication with our user via webhooks API. Let’s do that.

We need to visit URL, which can be constructed like this one

[plain]https://api.telegram.org/bot<telegram_bot_token_from_botfather>/setWebhook?url=<your_https_ngrok_url>/webhooks/telegram_<place_some_big_random_token_here>[/plain]

so, in my case it will be something like this

[plain]https://api.telegram.org/bot220521163:AAHNZe-njGuJz_6-zwOyR1BKkhyJoGpNPyo/setWebhook?url=https://bb157435.ngrok.io/webhooks/telegram_vbc43edbf1614a075954dvd4bfab34l1[/plain]

We need to place a random string at the end to make sure that nobody will guess it and get access to bot-vs-user communication.

If you’ve done everything ok, when visiting this URL you’ll see a success message which looks something like this:
telegram

So, this message means that all the message users send to your bot will go through your Rails application’s WebhooksController, which we are going to implement in a next step.

Open existing or create a new webhooks_controller.rb file and implement a method called telegram_vbc43edbf1614a075954dvd4bfab34l1

do not forget to add mapping to the routes.rb

Your WebhooksController will now look like this:

So, right now we have a controller action for receving incoming messages. Next step is to implement a plain Ruby class that will differentiate our messages and answer them correctly accordingly to the step user is now on. So, for these purposes we need to create a class called BotMessageDispatcher which will have a list of commands available for user.

Since we are writing a very simple quest game we need to define a command for each particular step of our game. One more thing we need to do to make our game work is to remember on which step is user now and not to jump across and between independent steps.

So, let’s decide what we will do in our quest game. I decided to go with ‘Becoming a Rails rockstar’ game which will have 3 simple steps:

  1. Born
  2. Accomplish your very first Rails tutorial
  3. Write a blog in 15 minutes

You are a real Rails rockstar!

So, to you can not accomplish any Rails tutorials without been born and also you can not write blog in 15 minutes without accomplishing any Rails tutorials. So, we need to take care about this and do not allow user to jump to step 2 without accomplishing step 1 and etc.

There where state storing is coming. We gonna create some methods for our User model to get current step, get next step, save current step and etc.

To do that let’s add jsonb field called ‘bot_command_data’ to our user model

Not to make this article really long here is the final implementation of these helper methods for User model

So, as you can see we implemented some very useful helpers which will help us to store and retrieve user state from database. Here you can see a word ‘bot_command’, so, we will build our user-bot communication with abstractions represented in a plain Ruby class called BotCommand.

We will create a base class with basic functionality and a class inherited from it for each command we need.

So, at first let’s implement our BotMessageDispatcher that will know which particular command to apply at any moment of bot-user communication.

Here it is:

Here you can see a constant array of all the commands we need and a method called ‘process’ which will figure out which command is user able to process now, save it, and then prepare user for processing next command.

So, we have a mechanism for dispatching messages, storing state, figuring out which command at each moment of user-bot communication. So, the last step of our implementation is to implement BotCommand class and separate class for each command. Let’s do it.

Our BotCommand class will actually send messages to users, so we need to install a Ruby gem for communication with Telegram to do that.

Just add this line to your Gemfile and do ‘bundle install’.

One more thing we need to send messages is our Telegram bot token, so let’s add it to the secrets.yml file in a key called ‘bot_token’.
For me it will be:

We are ready to go!

Here is how your BotCommand class will look like:

Here it is. We have a base class for our abstract BotCommand. Here we have a method for sending messages and 2 methods which need to be implemented in all the other command classes which will be inherited from the Base class.

So, let’s do that. The very first command is called Start and used to trigger Telegram bot to start conversation with our user.

Next command we need to implement is BotCommand::Born class.

Cool, we have been born, let’s try to accomplish our very first Rails tutorial.

Tutorial accomplished, your user knows a lot of stuff about Rails already. Let’s give him ability to write a blog and become a Rails rockstar.

Looks like we’ve done it. As you can see, our architecture is pretty simple and very flexible, so you are welcome to change it according to your needs.

Good luck in creating useful bots!

Maxim Abramchuk


  •  
  •  
  •  
  •  
  •  
  • 1

Comments

  1. […] Full Guide on Creating Telegram Bot that Stores State […]

Leave a Reply

Your email address will not be published. Required fields are marked *