diff --git a/CHANGELOG.md b/CHANGELOG.md index 83d7f74..2b283ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- `rescue_from`. + # 0.12.4 - Fix spec helpers for callback queries. diff --git a/README.md b/README.md index fd0f5cd..116872c 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,9 @@ can represent actions as separate methods keeping source much more readable and New instance of controller is instantiated for each update. This way every update is processed in isolation from others. +Bot controllers like usual rails controllers provides features like callbacks, +`rescue_from` and instrumentation. + ```ruby class Telegram::WebhookController < Telegram::Bot::UpdatesController # use callbacks like in any other controllers @@ -331,7 +334,7 @@ end # And this one is for `make_cool:%{something}` def make_cool_callback_query(thing = nil, *) do_it(thing) - answer_callback_query("#{thing} is cool now! Like a callback query context.") + answer_callback_query("#{thing} is cool now! Like a callback query context.") end ``` @@ -360,7 +363,7 @@ There are several options to run it automatically: - Use poller (described in the next section). To run action without update (ex., send notifications from jobs), -you can call `#process` directly. In this case controller can be initialized +you can call `#process` directly. In this case controller can be initialized with `:from` and/or `:chat` options instead of `update` object: ```ruby diff --git a/lib/telegram/bot/updates_controller.rb b/lib/telegram/bot/updates_controller.rb index 743b0fb..041201d 100644 --- a/lib/telegram/bot/updates_controller.rb +++ b/lib/telegram/bot/updates_controller.rb @@ -57,6 +57,7 @@ module Telegram instrumentation log_subscriber reply_helpers + rescue session ].each { |file| require "telegram/bot/updates_controller/#{file}" } @@ -78,6 +79,7 @@ module Telegram end include AbstractController::Translation + include Rescue include ReplyHelpers prepend Instrumentation extend Session::ConfigMethods diff --git a/lib/telegram/bot/updates_controller/rescue.rb b/lib/telegram/bot/updates_controller/rescue.rb new file mode 100644 index 0000000..3a13f8a --- /dev/null +++ b/lib/telegram/bot/updates_controller/rescue.rb @@ -0,0 +1,20 @@ +require 'active_support/rescuable' + +module Telegram + module Bot + class UpdatesController + module Rescue + extend ActiveSupport::Concern + include ActiveSupport::Rescuable + + private + + def process_action(*) + super + rescue Exception => exception # rubocop:disable RescueException + rescue_with_handler(exception) || raise + end + end + end + end +end diff --git a/spec/telegram/bot/updates_controller/rescue_spec.rb b/spec/telegram/bot/updates_controller/rescue_spec.rb new file mode 100644 index 0000000..ae03f76 --- /dev/null +++ b/spec/telegram/bot/updates_controller/rescue_spec.rb @@ -0,0 +1,31 @@ +RSpec.describe Telegram::Bot::UpdatesController::Rescue do + include_context 'telegram/bot/updates_controller' + + describe '#process_action' do + subject { -> { dispatch_message("/#{command} x y z") } } + + let(:controller_class) do + Class.new(Telegram::Bot::UpdatesController) do + rescue_from ArgumentError, with: -> { respond_with :message, text: 'Rescued' } + + def rescuable(*) + raise ArgumentError, 'rescuable' + end + + def not_rescuable(*) + raise 'not_rescuable' + end + end + end + + context 'when exception is rescued' do + let(:command) { :rescuable } + it { should respond_with_message 'Rescued' } + end + + context 'when exception is not rescued' do + let(:command) { :not_rescuable } + it { should raise_error('not_rescuable') } + end + end +end