Class: Telegram::Bot::UpdatesController

Inherits:
AbstractController::Base
  • Object
show all
Extended by:
Session::ConfigMethods
Includes:
AbstractController::Callbacks, Commands, Instrumentation, ReplyHelpers, Rescue, Translation
Defined in:
lib/telegram/bot/updates_controller.rb,
lib/telegram/bot/updates_controller/rescue.rb,
lib/telegram/bot/updates_controller/session.rb,
lib/telegram/bot/updates_controller/testing.rb,
lib/telegram/bot/updates_controller/commands.rb,
lib/telegram/bot/updates_controller/translation.rb,
lib/telegram/bot/updates_controller/typed_update.rb,
lib/telegram/bot/updates_controller/reply_helpers.rb,
lib/telegram/bot/updates_controller/log_subscriber.rb,
lib/telegram/bot/updates_controller/instrumentation.rb,
lib/telegram/bot/updates_controller/message_context.rb,
lib/telegram/bot/updates_controller/callback_query_context.rb

Overview

Base class to create update processors. With callbacks, session and helpers.

Public methods ending with ‘!` handle messages with commands. Message text is automatically parsed into method arguments. Be sure to use default values and splat arguments in every action method to not get errors, when user sends command without necessary args / with extra args.

def start!(token = nil, *)
  if token
    # ...
  else
    # ...
  end
end

def help!(*)
  respond_with :message, text:
end

To process plain text messages (without commands) or other updates just define public method with name of payload type. By default they receive payload as an argument, but some of them are called with more usefuk args:

def message(message)
  respond_with :message, text: "Echo: #{message['text']}"
end

def inline_query(query, offset)
  answer_inline_query results_for_query(query, offset), is_personal: true
end

To process update run:

ControllerClass.dispatch(bot, update)

There is also ability to run action without update:

ControllerClass.new(bot, from: telegram_user, chat: telegram_chat).
  process(:help, *args)

Defined Under Namespace

Modules: CallbackQueryContext, Commands, Instrumentation, MessageContext, ReplyHelpers, Rescue, Session, Testing, Translation, TypedUpdate Classes: LogSubscriber

Constant Summary collapse

PAYLOAD_TYPES =
Set.new(%w[
  message
  edited_message
  channel_post
  edited_channel_post
  business_connection
  business_message
  edited_business_message
  deleted_business_messages
  message_reaction
  message_reaction_count
  inline_query
  chosen_inline_result
  callback_query
  shipping_query
  pre_checkout_query
  purchased_paid_media
  poll
  poll_answer
  my_chat_member
  chat_member
  chat_join_request
  chat_boost
  removed_chat_boost
].freeze)

Constants included from Commands

Commands::CMD_REGEX

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Session::ConfigMethods

session_store=, use_session!

Methods included from Instrumentation

instrument, #process_action, #respond_with

Methods included from Translation

#action_name_i18n_key, #localize, #translate

Methods included from ReplyHelpers

#answer_callback_query, #answer_inline_query, #answer_pre_checkout_query, #answer_shipping_query, #edit_message, #reply_with, #respond_with

Methods included from Commands

#action_for_command, #action_for_message, command_from_text

Constructor Details

#initialize(bot = nil, update = nil, webhook_request = nil) ⇒ UpdatesController

‘update` can be either update object with hash access & string keys or Hash with `:from` or `:chat` to override this values and assume that update is nil. ActionDispatch::Request object is passed in `webhook_request` when bot running in webhook mode.



159
160
161
162
163
164
165
166
167
168
169
# File 'lib/telegram/bot/updates_controller.rb', line 159

def initialize(bot = nil, update = nil, webhook_request = nil) # rubocop:disable Lint/MissingSuper
  if update.is_a?(Hash) && (update.key?(:from) || update.key?(:chat))
    options = update
    update = nil
  end
  @_bot = bot
  @_update = update
  @_chat, @_from = options&.values_at(:chat, :from)
  @_payload, @_payload_type = self.class.payload_from_update(update)
  @_webhook_request = webhook_request
end

Class Method Details

.dispatch(*args) ⇒ Object

Initialize controller and process update.



120
121
122
# File 'lib/telegram/bot/updates_controller.rb', line 120

def dispatch(*args)
  new(*args).dispatch
end

.payload_from_update(update) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/telegram/bot/updates_controller.rb', line 124

def payload_from_update(update)
  case update
  when nil then nil
  when Hash
    # faster lookup for the case when telegram-bot-types is not used
    update.find do |type, item|
      return [item, type] if PAYLOAD_TYPES.include?(type)
    end
  else
    payload_from_typed_update(update)
  end
end

Instance Method Details

#action_for_callback_queryObject



244
245
246
# File 'lib/telegram/bot/updates_controller.rb', line 244

def action_for_callback_query
  [payload_type, [payload['data']]]
end

#action_for_chosen_inline_resultObject



240
241
242
# File 'lib/telegram/bot/updates_controller.rb', line 240

def action_for_chosen_inline_result
  [payload_type, [payload['result_id'], payload['query']]]
end

#action_for_default_payloadObject



232
233
234
# File 'lib/telegram/bot/updates_controller.rb', line 232

def action_for_default_payload
  [payload_type, [payload]]
end

#action_for_inline_queryObject



236
237
238
# File 'lib/telegram/bot/updates_controller.rb', line 236

def action_for_inline_query
  [payload_type, [payload['query'], payload['offset']]]
end

#action_for_payloadObject

Calculates action name and args for payload. Uses ‘action_for_#payload_type` methods. If this method doesn’t return anything it uses fallback with action same as payload type. Returns array ‘[action, args]`.



224
225
226
227
228
229
230
# File 'lib/telegram/bot/updates_controller.rb', line 224

def action_for_payload
  if payload_type
    send("action_for_#{payload_type}") || action_for_default_payload
  else
    [:unsupported_payload_type, []]
  end
end

#action_for_poll_answerObject



248
249
250
# File 'lib/telegram/bot/updates_controller.rb', line 248

def action_for_poll_answer
  [payload_type, [payload['poll_id'], payload['option_ids']]]
end

#action_missing(action, *_args) ⇒ Object

Silently ignore unsupported messages to not fail when user crafts an update with usupported command, callback query context, etc.



254
255
256
257
# File 'lib/telegram/bot/updates_controller.rb', line 254

def action_missing(action, *_args)
  logger&.debug { "The action '#{action}' is not defined in #{self.class.name}" }
  nil
end

#action_typeObject

There are multiple ways how action name is calculated for update (see Commands, MessageContext, etc.). This method represents the way how action was calculated for current udpate.

Some of possible values are ‘:payload, :command, :message_context`.



215
216
217
# File 'lib/telegram/bot/updates_controller.rb', line 215

def action_type
  action_options[:type] || :payload
end

#chatObject

Accessor to ‘’chat’‘ field of payload. Also tries `’chat’‘ in `’message’‘ when there is no such field in payload.

Can be overriden with ‘chat` option for #initialize.



175
176
177
178
179
180
181
182
183
184
# File 'lib/telegram/bot/updates_controller.rb', line 175

def chat # rubocop:disable Metrics/PerceivedComplexity
  @_chat ||= # rubocop:disable Naming/MemoizedInstanceVariableName
    if payload
      if payload.is_a?(Hash)
        payload['chat'] || (payload['message'] && payload['message']['chat'])
      else
        payload.try(:chat) || payload.try(:message)&.chat
      end
    end
end

#dispatchObject

Processes current update.



194
195
196
197
# File 'lib/telegram/bot/updates_controller.rb', line 194

def dispatch
  action, args = action_for_payload
  process(action, *args)
end

#fromObject

Accessor to ‘’from’‘ field of payload. Can be overriden with `from` option for #initialize.



188
189
190
191
# File 'lib/telegram/bot/updates_controller.rb', line 188

def from
  @_from ||= # rubocop:disable Naming/MemoizedInstanceVariableName
    payload.is_a?(Hash) ? payload['from'] : payload.try(:from)
end

#process(action, *args) ⇒ Object

It provides support for passing array as action, where first vaule is action name and second is action metadata. This metadata is stored inside action_options



204
205
206
207
208
# File 'lib/telegram/bot/updates_controller.rb', line 204

def process(action, *args)
  action, options = action if action.is_a?(Array)
  @_action_options = options || {}
  super
end