記事紹介:devise のモデルを分割して単一責任の原則を導入する

2 min read読了の目安(約2100字

2021/2/18 追記:
多少は理解したので実施した記事を書きました

追記終わり


こんにちは。北山です。
今回も失敗談ですが、参考にしていた記事は共有したいので記事にしました。
(はてブでやれって話はある)

TL;DR

devise のデフォルトで実装すると User モデルがヤバイ事になる

https://github.com/heartcombo/devise

devise は Rails で認証認可の必要なサービスを作る時に
スタンダードな gem としてとても有名な物です。
メールアドレス+パスワードでの認証だけでなく、
メールアドレスの有効性の確認やTwitter認証なども簡易に組み込むことができ、
認証認可のシステムとして押さえておきたい部分は大体揃ってますね。

ただ、私としてはただ1つ気になるところがあって
関連する全ての情報を Userモデル(usersテーブル)で管理する設計になっていることです。

note のレスポンスにIPアドレスが含まれていて話題になった話を覚えている人もいると思います。

https://www.itmedia.co.jp/news/articles/2008/14/news088.html
https://www.itmedia.co.jp/news/articles/2009/30/news146.html

まぁこれは適切にレスポンスを組むようにしよう、という話で終わりでもいいんですが、
とはいえ devise の標準に則って User モデル(usersテーブル)を作成すると

  • id (Userを一意に決める情報。Railsデフォルトだと自動インクリメントのPK)
  • ユーザー名
  • email
  • 暗号化済みpassword
  • パスワードリセット用のトークン
  • パスワードリセットメールの送信日時
  • サインイン回数カウンタ
  • 現在のサインイン日時
  • 最終サインイン日時
  • 現在のサインインIPアドレス
  • 最終サインインIPアドレス
  • メールアドレス認証用トークン
  • メールアドレス認証日時
  • 認証用メールアドレスにメール送信した日時
  • パスワード入力失敗回数
  • パスワード入力失敗によるアカウントロック解除用トークン
  • パスワード入力失敗によるアカウントロック実施日時
  • OmniAuth認証プロバイダ
  • OmniAuth認証uid
  • OmniAuth認証ユーザ名
    ...

というような情報がどんどん User モデル(usersテーブル) に追加していく設計になっています。
これはつまり、パスワードリセットするときも Userモデルが更新されるし
サインインした時もUserモデルが更新されるし
パスワードロックした時も……

という風にどんどん usersテーブルのカラムが増大していき、
それぞれの処理も Userモデル に追加されていくので Userモデル が肥大化します。

これは、 単一責任の原則 からするとアンチパターンな状態と言えるでしょう。

どう解決するのか

それを解決する方法を紹介してくれているのが冒頭に挙げた記事です。

https://joker1007.hatenablog.com/entry/2020/08/17/141621

この記事では、Userモデル以外に deviseのモジュールごとに
必要な Model を作成することで
Userモデルの肥大化を防ぎ、Model の責務分割を実現しています。

また、そのような Model 分割を行った場合に
どのように devise で提供されているコントローラやビューと統合することができるか
解説されていてわかりやすいです。

まさに「私が今求めていた物」という感じでうれしかったです。

ただし筆者は現在挫折中……

ある程度は記事で解説してくれてるといっても、
やはり応用の部分(Twitter認証を追加するときはどうするか)などは
devise の実装をよく理解してやっていく必要があり、
私は devise の実装をまだ追い切れていないため
記事に書いてあること以上のことをやろうとして挫折しました。
もっと勉強しないと……

この記事を見て気になった方は、
ぜひ一緒にチャレンジしてみましょう。
うまく形になった時には見通しの良い認証認可基盤ができていることは間違いないと思います。