$shibayu36->blog;

株式会社アンドパッドでエンジニアをしています。プログラミングや読書のことなどについて書いています。

before_actionなどのCallbacksに登録されているものを知る方法

と悩んでいたが、方法を教えてもらえたり、便利なツールを発見したりしたのでメモ。方法は二つ。

  • 特定アクションアクセス時に登録されているCallbacksを全て表示する
  • Callbacksが呼ばれたときにログを出力

特定アクションアクセス時に登録されているCallbacksを全て表示する

Debugging Action Callbacks (aka Filters) in Rails | Hashrocket

pry-railsを使い、_process_action_callbacksを見ることで、実行予定のCallbacksを全て表示するという方法がある。

pry-railsをインストールした後に、出力したいアクションの周囲に以下のコードを入れる。

  prepend_before_action do
    require 'pry'
    binding.pry
    true
  end

その後、そのアクションが実行されるURLにアクセスすると、pryが立ち上がるので、_process_action_callbacksを呼ぶと良い。すると以下のように出力され、このアクションではどのCallbacksが実行予定なのかを把握することが可能だ。

f:id:shiba_yu36:20211114164836p:plain

Callbacksが呼ばれたときにログを出力

先程の作戦は、特定アクションに紐づく一覧を全て出力する形式だった。一方で実際に呼ばれたものだけ表示したいという場合もある。このような時は、以下のようなツールを使い、呼ばれた場合にログを出力することもできる。

github.com

これを使い、tail -F log/action_tracer.log することで、何が登録されていて、何が適用されているかが一目瞭然となる。便利。

I, [2021-11-15T11:19:21.482139 #71440]  INFO -- : ["NO_APPLIED", :Proc, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/devise-4.8.0/app/controllers/devise/sessions_controller.rb", 7]
I, [2021-11-15T11:19:21.482214 #71440]  INFO -- : ["NO_APPLIED", :verify_signed_out_user, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/devise-4.8.0/app/controllers/devise/sessions_controller.rb", 61]
I, [2021-11-15T11:19:21.482243 #71440]  INFO -- : ["NO_APPLIED", :allow_params_authentication!, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/devise-4.8.0/lib/devise/controllers/helpers.rb", 163]
I, [2021-11-15T11:19:21.482270 #71440]  INFO -- : ["APPLIED", :require_no_authentication, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/devise-4.8.0/app/controllers/devise_controller.rb", 102]
I, [2021-11-15T11:19:21.482315 #71440]  INFO -- : ["APPLIED", :assert_is_devise_resource!, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/devise-4.8.0/app/controllers/devise_controller.rb", 64]
I, [2021-11-15T11:19:21.482345 #71440]  INFO -- : ["APPLIED", :verify_authenticity_token, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/actionpack-6.1.4.1/lib/action_controller/metal/request_forgery_protection.rb", 227]
I, [2021-11-15T11:19:21.482377 #71440]  INFO -- : ["APPLIED", :set_turbolinks_location_header_from_session, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/turbolinks-5.2.1/lib/turbolinks/redirection.rb", 43]
I, [2021-11-15T11:19:21.482457 #71440]  INFO -- : ["APPLIED", :Proc, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/actiontext-6.1.4.1/lib/action_text/engine.rb", 58]
I, [2021-11-15T11:19:21.482487 #71440]  INFO -- : ["ACTION", "new", "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/devise-4.8.0/app/controllers/devise/sessions_controller.rb", 10]
I, [2021-11-15T11:19:21.482516 #71440]  INFO -- : ["APPLIED", :Proc, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/actiontext-6.1.4.1/lib/action_text/engine.rb", 58]
I, [2021-11-15T11:19:21.482533 #71440]  INFO -- : ["APPLIED", :verify_same_origin_request, "/Users/yuki.shibazaki/.anyenv/envs/rbenv/versions/2.7.4/lib/ruby/gems/2.7.0/gems/actionpack-6.1.4.1/lib/action_controller/metal/request_forgery_protection.rb", 257]
I, [2021-11-15T11:19:21.482552 #71440]  INFO -- :

Auth0でユーザーがMFAの設定をしている時のみMFA検証フォームを出す

ユーザー設定画面にMFAの設定画面があり、それが設定されているときだけログイン後にMFAのフォームを出したいという要求はよくある。これをAuth0を使っている場合に達成したかった。しかし、Enable Multi-Factor Authenticationなどを見ても、全体に有効/無効しか切り替えられないようで困っていた。

いろいろ調べたところやる方法が分かったのでメモしておく。

ユーザー向けのMFA設定画面を自分のアプリケーションに実装する方法

まずユーザー向けのMFA設定画面を自分のアプリケーションに実装するには、Auth0のMFAリソースに対する権限を持ったアクセストークンを取得する必要がある。詳しくはManage Authenticator Factors with Auth0 MFA APIに書かれているが

  • Auth0のApplication設定画面でGrant TypesにMFAを追加
  • ログインなどのリクエスト時に、audienceの指定を https://YOUR_DOMAIN/mfa/とする。さらにScopesを適切につける。関係するのはenroll, read:authenticators, remove:authenticatorsの三つ

これで取得したアクセストークンであれば、MFAのenrollや登録したMFA認証の一覧取得などをAPI経由で行えるようになる。このAPIを使ってユーザー向けの設定画面を実装すれば良い。

MFAを設定している場合だけログイン後にMFA検証フォームを出す

Auth0 ActionsAuth0 Rulesを使う必要がある。自分はActionsを使って実装してみた。

event.user.multifactorにユーザーがenrollしているMFAのプロバイダ一覧が入っているので、一つでも設定していたらフォームを出すようにする。以下のコードで可能。

exports.onExecutePostLogin = async (event, api) => {
  if (event.user.multifactor && event.user.multifactor.length > 0) {
    api.multifactor.enable(“any”)
  }
};

git grepの結果に、その行を書いたAuthorを表示する

あまり知らないコードを触るときに、周りのコードを参考にしたいことが多い。しかし、そのコードの技術スタックに詳しくない場合、どのコードは筋が良いかというのが全く分からないことがある。そういう時に、その分野に知見がある人が書いたコードを参考にしながら学習したい。

そのように知見を素早く吸収するために、git grepの結果に、その行を書いたAuthorを表示するとどうかと思ったのでやってみた。

git-grep-with-author

#!/bin/bash

git grep -n "$@" | while IFS=: read i j k
do
  author=$(git blame -L $j,$j $i --line-porcelain | grep '^author ' | cut -d' ' -f2-)
  echo -e "$i:$j:$author:$k"
done

例えばRailsのrepositoryで使うと

$ git-grep-with-author ActiveModel
actionpack/lib/action_controller/metal/params_wrapper.rb:52:Prem Sichanugrist:  # If you're going to pass the parameters to an +ActiveModel+ object (such as
actionpack/lib/action_controller/metal/strong_parameters.rb:260:Francesco Rodriguez:    #   Person.new(params) # => ActiveModel::ForbiddenAttributesError
actionpack/lib/action_controller/metal/strong_parameters.rb:424:Francesco Rodriguez:    #   Person.new(params) # => ActiveModel::ForbiddenAttributesError
actionpack/lib/action_controller/metal/strong_parameters.rb:873:Prem Sichanugrist:    # This is required by ActiveModel attribute assignment, so that user can
actionpack/lib/action_controller/metal/strong_parameters.rb:1157:yuuji.yaginuma:  #     # ActiveModel::ForbiddenAttributesError exception because it'd
actionpack/test/controller/redirect_test.rb:6:Jon Moss:  extend ActiveModel::Naming
actionpack/test/controller/redirect_test.rb:7:Jon Moss:  include ActiveModel::Conversion

のようにファイル名と行の後に、Authorを出してくれるようになった。便利。