現在携わっているプロダクトでは、ActiveAdminを利用して管理画面を開発しています。 提供されているDSLを記述することで、リソース(モデル)ごとに管理画面に必要なコントローラー、フォームなどのビューを作成することができるので便利です。
自動的にコントローラーが生成されるのですが、それら全体に対してbefore_action
などを追加したくなる場合があります。
ここではその方法について説明します。
前提
まず前提として、ActiveAdminが生成するコントローラーは、そのRailsアプリケーションのApplicationController
を継承します。
ですので、そこで定義されているbefore_action
が定義されていれば、それはActiveAdminのコントローラーにも適用されることになります。
以下では、アプリケーションモニタリングサービスのSentryへ送る情報を切り替える場合を例に具体的な実装を見ていきます。
Sentryにユーザー情報を送る
sentry-rails
を使うと、Railsアプリケーションで例外が発生するとその例外やその時のパラメーターなどをSentryに送ることができます。
この情報に、そのときにログインしているユーザーの情報を送りたい場合があります。
以下のようにbefore_action
を追加すると、ログインしている場合にそのユーザーのIDとユーザー名、メールアドレスを送ることができるようになります。
class ApplicationController < ActionController::Base
before_action :set_sentry_context
private
def set_sentry_context
Sentry.set_user(id: current_user.id, username: current_user.name, email: current_user.email) if current_user
end
end
ActiveAdminのときは管理者の情報を送る
このままだと、ActiveAdminの画面で例外が発生した場合にも、ユーザーとしてログインしていればその情報がSentryに送られてしまいます。
そこで、Sentryの設定でActiveAdminのリソースのコントローラーのみにbefore_action
を追加します。
config/initializers/active_admin.rb
に下記の1行を追加します。
ActiveAdmin.setup do |config|
config.before_action = :set_sentry_context_for_active_admin # Add this line
end
このset_sentry_context_for_active_admin
自体は、先程と同じApplicationController
に追加します。
class ApplicationController < ActionController::Base
before_action :set_sentry_context
private
def set_sentry_context
Sentry.set_user(id: current_user.id, username: current_user.name, email: current_user.email) if current_user
end
def set_sentry_context_for_active_admin
Sentry.set_user(id: current_admin_user.id, email: current_admin_user.email) if current_admin_user
end
end
このままでも十分に期待した通りの動作をするのですが、set_sentry_context
とset_sentry_context_for_active_admin
の両方が実行されてしまいます。
もしset_sentry_context
に他にもユーザー向けに実行するロジックがあるとすれば、副作用が起きる可能性があります。
そもそもset_sentry_context
はActiveAdminでは不要なので、skip_before_action
で不要な処理を実行しないように設定します。
ActiveAdmin.setup do |config|
config.before_action = :set_sentry_context_for_active_admin
config.skip_before_action = :set_sentry_context
end