Madogiwa Blog

主に技術系の学習メモに使っていきます。

ActiveSupport::ActionableErrorを使って例外発生時に画面から任意の処理を実行するメモ📝

Rails 6から導入されたActiveSupport::ActionableErrorを使うと例外発生時に画面から任意の処理が実行できて便利そうだったので使い方とかをメモ📝

github.com

Rails標準ではActiveRecord::PendingMigrationErrorが発生時にこちらを使ってmigrationが行えるようになってますね!

この機能は通常のRails例外ページにボタンを追加し、ブラウザのエラーページでマイグレーションを実行してActiveRecord::PendingMigrationErrorエラーを解決できるようにします。 Rails 6のB面に隠れている地味にうれしい機能たち(翻訳)|TechRacho by BPS株式会社

ActiveSupport::ActionableErrorの使い方

使い方は簡単で、ActiveSupport::ActionableError

class MyException < StandardError
  include ActiveSupport::ActionableError

  action 'Oops!!' do
    puts 'Oops!! raised MyException!!'
  end
end

class PostsController < ApplicationController
  def new
    raise MyException
  end
end

表示されているOops!!をクリックすると以下のようにログにactionに定義したputs 'Oops!! raised MyException!!'が実行されて結果が出力されています。

Oops!! raised MyException!!

任意を例外をActionableにする

以下のようなmoduleを使ってinitializerとかでrequireをすると既存の任意のエラーをActionableErrorにすることができると思います。

require 'active_support/all'

module EnableActionableError
  extend ActiveSupport::Concern

  included do
    include ActiveSupport::ActionableError

    action 'Oops!!' do
      puts 'your any process.'
    end
  end
end

TargetError.include(EnableActionableError)

(出来なかった)webpackのbuildがされてなかったらボタンクリックでbuildできるようにしたい

個人のサービスではsimpackerを使っているのでyarn buildが行われていなかった時にしたくて以下のようなファイルを作ってrequireはしてみたのですが、上手くいかなかった・・・😭

# frozen_string_literal: true

require 'simpacker/manifest'
require 'active_support/all'
require 'action_view/template/error'

module Patches
  module Simpacker
    module EnableActionableError
      extend ActiveSupport::Concern

      included do
        include ActiveSupport::ActionableError

        action 'Run yarn build for development' do
          system 'yarn build:dev'
        end
      end
    end
  end
end

# MEMO
# Simpacker::Manifest::MissingEntryErrorがControllerで直接発生する場合にはいい感じに動作するが、
# `<%= javascript_pack_tag 'boards/new' %>`のような形でerb内で発生した場合には、
# `ActionView::Template::Error`になってしまうのでPatchが効かない。
# `ActionView::Template::Error`に直接includeしてもなぜか動かないが、
# そもそも`ActionView::Template::Error`にactionを設定するのは微妙な気がする。。。

Simpacker::Manifest::MissingEntryError.include(Patches::Simpacker::EnableActionableError)
Simpacker::Manifest::MissingFileError.include(Patches::Simpacker::EnableActionableError)
# ActionView::Template::Error.include(Patches::Simpacker::EnableActionableError)

Rails、template内で例外が発生すると、メッセージとかは実際の例外のものになるが実態はActionView::Template::Errorがraiseされているのと、ActionView::Template::Errorに直接includeしてもなぜか動かない。。。(そもそもActionView::Template::Errorにactionを設定するのは微妙な気がする。。。

The Template::Error exception is raised when the compilation or rendering of the template fails. This exception then gathers a bunch of intimate details and uses it to report a precise exception message.
rails/error.rb at 18707ab17fa492eb25ad2e8f9818a320dc20b823 · rails/rails · GitHub

おわりに

ActiveSupport::ActionableError、手軽に使えるのと、色々出来て便利そうですね!

参考

api.rubyonrails.org

www.bigbinary.com