概要

最近、Railsで認証のためにDeviseを使っていた際に、authenticatedというものを知ったので、それの紹介をします。

環境

  • Rails 5.1
  • Devise 4.4

ルーティング

認証をしていると、認証した人だけアクセスさせたいページが出てくると思います。

そこで、Deviseではauthenticatedというものがあり、それを使うと認証した人だけアクセスできるルーティングを追加することができます。

例を見た方が早いので、例を出します。

これは、config/routes.rbの内容で、DeviseのモデルはUserという名前の場合の例です。

Rails.application.routes.draw do
  authenticated :user do
    namespace :admin do
      resources :articles
    end
  end
end

モデルの名前がUserでない場合は、:userの部分を変えましょう。

このようにすることで、認証された場合に限り、admin以下にあるルーティングが定義され、そこへアクセスできるようになります。

方法は、authenticated :userのように書いて、do-endで認証したときに定義するルーティングを記述するだけです。

管理者の判定

認証しただけでなく、さらに管理者である場合にルーティングを定義したいということがあると思います。

その場合には、ラムダ式を指定して次のようにします。

Rails.application.routes.draw do
  authenticated :user, lambda { |u| u.admin? } do
    namespace :admin do
      resources :articles
    end
  end
end

ラムダ式の結果がtrueの時にルーティングが定義されます。

このラムダ式では、u変数にdeviseのインスタンスが代入されるので、インスタンスのadminフラグがtrueの時にルーティングを定義するようになります。

もちろん、ここではadminフラグの結果でルーティングの定義を決めていますが、adminフラグ以外でも判定することは可能です。

テスト

おまけで、テストについても書いておきます。

authenticatedでルーティングを定義した際に、もしログインしていないのにアクセスしようとした際は、Not Foundが返されます。

なので、テストは次のようにします。

test 'should not get admin when not logged in' do
  assert_raises(ActionController::RoutingError) do
    get admin_url
  end
end

assert_raisesでNot Foundの例外が発生することを確認します。

さいごに

コントローラにbefore_action :authenticate_userのように書いても、認証をしていない場合にアクセスさせないということを実現できます。

コントローラに書く方が、細かい設定をできますが、設定が分散するので、ルーティングにauthenticatedを書く方で解決できるのであれば、こちらを書くようにした方がいいと思います。