SidekiqのDashboard等をmountしたengineの画面をログイン必須にしたい時、特定のサブドメインのときだけアクセス可能にしたい等、Rails のルーティングのconstraints
を使うと実現できそうだったので、そのあたりをメモしておきます📝
Rails のルーティングのconstraints
とは?
constraints
とはRoutingになんかしらの条件を与え、条件に合致しない場合にはActionController::RoutingError
を発生させることができる機能です。
以下のような形でサブドメインがadminのときの場合だけアクセス化にしたり任意の制約を設定することが出来ます。
namespace :admin do constraints subdomain: 'admin' do resources :users end end
Railsで必要なmatches?に応答できるオブジェクトを渡す方法があります。
また上記の通りmatches?
に応答できるオブジェクトを渡して制約を設定することも出来ます。
mountしたengineの画面をログイン必須する
SidekiqのDashboard等をmountしたengineの画面をログイン必須にしたい時に、このconstraint
を利用すると便利です。
以下のようにrequest
のsesison
からログインしている管理ユーザーのIDを取得して、そのユーザーが実際に登録されているユーザーの場合だけアクセス可能にするようなことが出来ます。
class AdminAuthConstraint def matches?(request) return false unless request.session[:admin_user_id] !!AdminUser.find_by(id: request.session[:admin_user_id]) end end Rails.application.routes.draw do namespace :admin do require 'sidekiq/web' mount Sidekiq::Web, at: '/sidekiq', constraints: AdminAuthConstraint.new end end
Deviseではこの辺をもっと簡単にできるauthenticated
が提供されていて以下のような形で行えるようになっています。
Rails.application.routes.draw do authenticated :admin_user do require 'sidekiq/web' mount Sidekiq::Web, at: '/sidekiq' end end end
中身はwarden
にアクセスしてスコープを考慮して認証済かどうかを確認し、ブロック引数があればそれを実行しているって感じみたいですね👀
def authenticated(scope = nil, block = nil) constraints_for(:authenticate?, scope, block) do yield end end def constraints_for(method_to_apply, scope = nil, block = nil) constraint = lambda do |request| request.env['warden'].send(method_to_apply, scope: scope) && (block.nil? || block.call(request.env["warden"].user(scope))) end constraints(constraint) do yield end end