Edited at

Rails でアカウントロジックを扱うなら sorcery が良いかも

More than 1 year has passed since last update.


導入文

Rails でアカウントロジック(ユーザ認証やSNSログイン)を扱いたい場合、大体 devise を使うというのが定石っぽい風潮であるように思われるのですが、ある程度アカウントロジックにかかわる機能を自分で自由に扱いたい場合は sorcery を使うとシンプルに出来るんじゃないだろうか、と思って試した結果、結構シンプルに扱えたので良かったという内容です。


公式サイト

https://github.com/NoamB/sorcery

です。devise で四苦八苦した経験をお持ちの方であれば、README.md や wiki をざっと読むだけで扱えるかと思います。


インストール

最低限必要なファイルについては rails generate sorcery:install で生成されます。


console

$ cd /path/to/your-awesome-rails-app/

$ echo "gem 'sorcery', '~> 0.9.1'" >> Gemfile
$ bundle install
$ bundle exec rails generate sorcery:install


共通設定+SNSログイン設定

sorcery に関する設定は config/initializers/sorcery.rb に記述します。 devise で SNS ログインを扱う場合 omniauth を併用する必要がありますが、sorcery の場合は sorcery だけで完結できてシンプルです。

Rails.application.config.sorcery.submodules には、本来のアカウントロジックに加えて扱いたい機能を列挙することができます。記事執筆時点でデフォルトとして揃っているのは


  • Eメールによるユーザアクティベーション (:user_activation)

  • HTTP ベーシック認証 (:http_basic_auth)

  • ログイン状態の維持 (:remember_me)

  • パスワードを忘れた場合の再設定 (:reset_password)

  • セッションタイムアウト (:session_timeout)

  • ブルートフォース防御 (:brute_force_protection)

  • 最後にログインしたのはいつか、などアカウントアクティビティの記録 (:activity_logging)

  • 外部サイト認証 (:external)

です。「あの機能が使いたいのに!」というのはほぼ揃っている感じですね。

下記は「twitterとfacebookのログイン機能を使いたい場合」の設定例です。必要値は適時準備してください。


config/initializers/sorcery.rb

# 扱いたい機能

Rails.application.config.sorcery.submodules = [:external]
Rails.application.config.sorcery.configure do |config|
# 対応するプロバイダ
config.external_providers = [:twitter, :facebook]
# Twitter 固有の設定
config.twitter.key = ENV["CONFIG_TWITTER_KEY"]
config.twitter.secret = ENV["CONFIG_TWITTER_SECRET"]
config.twitter.callback_url = ENV["CONFIG_TWITTER_CALLBACK_URL"]
config.twitter.user_info_mapping = { name: "screen_name", sns_icon_image: "profile_image_url_https" }
# Facebook 固有の設定
config.facebook.key = ENV["CONFIG_FACEBOOK_KEY"]
config.facebook.secret = ENV["CONFIG_FACEBOOK_SECRET"]
config.facebook.callback_url = ENV["CONFIG_FACEBOOK_CALLBACK_URL"]
config.facebook.user_info_mapping = { email: "email", name: "name", sns_icon_image: "picture/data/url" }
config.facebook.user_info_path = "me?fields=email,name,picture"
config.facebook.access_permissions = ["public_profile", "user_about_me", "email"]
config.facebook.scope = "public_profile,user_about_me,email"
config.facebook.display = "page"
config.facebook.api_version = "v2.5"
# ユーザモデルに関する設定
config.user_config do |user|
# 外部サイト認証に関するデータを扱うモデル
user.authentications_class = Authentication
end
# ユーザモデルをどのクラスで扱うか
config.user_class = "User"
end

twitter や Facebook 以外の外部サイト認証についても対応されています。詳しくはこちらでご確認下さい。


モデルについて

モデルは基本設定を特に変更しなければ、devise と同様 User モデルを扱う形になります。

パスワードの検証はデフォルトで「同じパスワードを2回入力し、合致するかどうかを検証する」方式になっています。バリデーションの if では


  • ユーザー新規登録時か (new_record?)

  • 既存パスワードを変更する場合か (changes[:crypted_password])

がチェックされています。


app/models/user.rb

class User < ActiveRecord::Base

authenticates_with_sorcery! do |config|
config.authentications_class = Authentication
end
accepts_nested_attributes_for :authentications
validates :password, presence: true, length: { minimum: 8 }, if: -> { new_record? || changes[:crypted_password] }
validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] }
validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] }
end


routes.rb について

ルーティングは以下のような形になります。外部サイト認証の場合 /oauth/* が必要となるので、追記します。


config/routes.rb

  resources :user_sessions

resources :users
get 'login' => 'user_sessions#new', as: :login
get 'logout' => 'user_sessions#destroy', as: :logout
get 'oauths/oauth'
get 'oauths/callback'
post "oauth/callback" => "oauths#callback"
get "oauth/callback" => "oauths#callback"
get "oauth/:provider" => "oauths#oauth", as: :auth_at_provider


コントローラとビューについて

ユーザの新規作成や編集、削除(退会)については users_controller.rb で、ログイン・ログアウトについては user_sessions_controller.rb で、外部サイト認証は oauths_controller.rb で扱う形です。

ビューについては devise でお馴染みのヘルパメソッド current_user を用いて、似たようなロジックを使うことができます。

公式ドキュメント(wiki)では以下の箇所が参考になります。基本的には書いてあるコードサンプルを順番に作っていけばそれでいいような感じになっており、なかなかシンプルです。


devise と比べてどこが良いのか

devise ではある程度定められたアカウントロジックが提供されるものの、その「ある程度定められたアカウントロジック」を少しカスタマイズしたいなどと言った場合(内容にもよりますが)途端にメンテナンスが難しくなります。

これに対する sorcery のアプローチは「必要なものはあるから適時作成したりしなかったりして欲しい」というようなものになるかと思います。devise がフルスタックであるのに対し、sorcery はアカウントロジックの一挙一動(どこで何を実行するか)を自分で記述しなければならない手間はあるものの「書いたものだけが動く」という点においてはシンプルであり、そのような視点においては devise よりも見通しの良いアカウントロジックを構築することができます。

なので「gem をインストールして rails generate sorcery:install すればコントローラもビューもモデルもバババーンと揃ってスパパパーンと動いてイージー」ということにはならないため、そういう意味での面倒臭さはありますが、メンテナンス性などを考慮するのであれば、利用する価値は十分あるのではないかと感じました。

devise をある程度経験した方であればすんなり学習可能な gem だと思います。

※ 個人的には外部サイト認証を利用する際に omniauth など複数の gem を定義しなくてもよい点が好きです