Slide 1

Slide 1 text

テーブル分割で実現する Deviseの責務の分離と柔軟な削除機構 Kaigi on Rails 2023 なおと 2023/10/28

Slide 2

Slide 2 text

⾃⼰紹介 • サーバーサイドエンジニア • Doorkeeperが好き • エンジニア2年⽣、初登壇 @NaotoCoding なおと

Slide 3

Slide 3 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 4

Slide 4 text

その前に。 Deviseにおけるusersテーブルの分割については、 jokerさんのブログ記事 「パーフェクトRails著者が解説するdeviseの現代的なユーザー 認証のモデル構成について」 を参照し、⾃分の中で噛み砕きながらDeviseのテーブル構造に ついて考えました。 https://joker1007.hatenablog.com/entry/2020/08/17/141621

Slide 5

Slide 5 text

1. Deviseにおけるusersテーブルの分割

Slide 6

Slide 6 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 7

Slide 7 text

• 認証機構を簡単に作成可能にするgem • サインイン • サインアップ • サインアウト • ユーザーの記憶 • gem Wardenがベース a. Deviseとは 引⽤: https://github.com/heartcombo/devise

Slide 8

Slide 8 text

• 様々なオプションが提供されている • メール確認機能 • ログイン複数回失敗時にロック • オプションもとても簡単に有効化可能 • テーブルにカラムを追加 • モデルクラスでモジュールを使⽤するだけ 引⽤: https://github.com/heartcombo/devise a. Deviseとは

Slide 9

Slide 9 text

とても便利で超有名なgem 新規アプリ開発時には毎回お世話になっている a. Deviseとは

Slide 10

Slide 10 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 11

Slide 11 text

b. Deviseをこんな⾵に使いたいな 1. 1つのモデルクラスが1つの責務を担当するようにしたい 2. 雑な独⾃実装で不要な情報露出を⾏わせない

Slide 12

Slide 12 text

Deviseはさまざまなオプション機能を提供している • メール確認 • ログイン複数回失敗時ににロック 1. 1つのモデルクラスが⼀つの責務を担当するようにしたい b. Deviseをこんな⾵に使いたいな

Slide 13

Slide 13 text

Deviseはさまざまなオプション機能を提供している → 機能を追加するためにUserクラスでモジュールを読み込む 1. 1つのモデルクラスが⼀つの責務を担当するようにしたい b. Deviseをこんな⾵に使いたいな

Slide 14

Slide 14 text

Deviseはさまざまなオプション機能を提供している → 機能を追加するためにUserクラスでモジュールを読み込む → Userクラスが提供する機能(責務)が多くなる 1. 1つのモデルクラスが⼀つの責務を担当するようにしたい b. Deviseをこんな⾵に使いたいな

Slide 15

Slide 15 text

認証⽤テーブル、クラスを使って責務を分担させたいな、、、 1. 1つのモデルクラスが⼀つの責務を担当するようにしたい b. Deviseをこんな⾵に使いたいな

Slide 16

Slide 16 text

オプション機能を追加するとカラムがusersテーブルに付与される 2. 雑な独⾃実装で不要な情報露出を⾏わせない b. Deviseをこんな⾵に使いたいな

Slide 17

Slide 17 text

認証関連情報がusersテーブルに集約されているため Deviseが提供していない認証系機能を追加する際に usersテーブルにカラムを追加してしまう → 不要な情報の露出が⾏われるかも 2. 雑な独⾃実装で不要な情報露出を⾏わせない b. Deviseをこんな⾵に使いたいな

Slide 18

Slide 18 text

例 : ソーシャルログインの追加 2. 雑な独⾃実装で不要な情報露出を⾏わせない b. Deviseをこんな⾵に使いたいな

Slide 19

Slide 19 text

usersテーブルに以下のカラムを追加する⽅法がよく⾒られる 純粋なユーザー情報ではなく、認証⽤の情報であるため 本来別のテーブルに配置するべき情報だと考えている • provider:認証プロバイダーの名称 • uid:プロバイダーから受け取るuid 2. 雑な独⾃実装で不要な情報露出を⾏わせない b. Deviseをこんな⾵に使いたいな

Slide 20

Slide 20 text

雑にレコードをrenderした時uidやproviderまで送信してしまう (これは明らかなヒューマンエラーである) 2. 雑な独⾃実装で不要な情報露出を⾏わせない b. Deviseをこんな⾵に使いたいな

Slide 21

Slide 21 text

注意 あくまで不要な情報露出は 標準以外の認証系機能を追加した際に発⽣し得る懸念 Deviseが標準で⽤意している追加機能においては この点のセキュリティは担保されている (confirmed_atやencrypted_passwordなど) 2. 雑な独⾃実装で不要な情報露出を⾏わせない b. Deviseをこんな⾵に使いたいな

Slide 22

Slide 22 text

不要な情報の外部送信はできる限り避けたいな、、、 usersテーブルは純粋なユーザーの情報だけ置きたいな 2. 雑な独⾃実装で不要な情報露出を⾏わせない b. Deviseをこんな⾵に使いたいな

Slide 23

Slide 23 text

実際にテーブル分割を⾏ってみた

Slide 24

Slide 24 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 25

Slide 25 text

c. テーブル分割⽅法の提案 テーブル分割を⾏う⼿法での⼀例として、以下の⼿順を提案する 1. 機能に必要なカラムのみを別テーブルに分割 2. モデルクラスで必要なモジュールのみを使⽤ 3. 挙動に合わせて設定

Slide 26

Slide 26 text

例 : メールアドレスとパスワードでのサインイン機能 ビューはDeviseのデフォルトを使⽤ c. テーブル分割⽅法の提案

Slide 27

Slide 27 text

サインインに必要なカラムはemailとencrypted_password 1. 機能に必要なカラムのみを別テーブルに分割 c. テーブル分割⽅法の提案

Slide 28

Slide 28 text

サインインに必要なカラムはemailとencrypted_password 1. 機能に必要なカラムのみを別テーブルに分割 c. テーブル分割⽅法の提案

Slide 29

Slide 29 text

UserDatabaseAuthenticationクラス database_authenticatable: パスワードの暗号化や認証 validatable: メールアドレス、パスワードのバリデーション 2. モデルクラスで必要なモジュールのみを使⽤ c. テーブル分割⽅法の提案

Slide 30

Slide 30 text

Userクラス authenticatable: セッション管理やメソッドの提供 2. モデルクラスで必要なモジュールのみを使⽤ c. テーブル分割⽅法の提案

Slide 31

Slide 31 text

Userクラス authenticatable: セッション管理やメソッドの提供 2. モデルクラスで必要なモジュールのみを使⽤ • authenticate_user! • user_signed_in? • current_user c. テーブル分割⽅法の提案

Slide 32

Slide 32 text

Userクラス authenticatable: セッション管理やメソッドの提供 → 認証⽅法が複数存在してもセッション管理はUserクラスが担う 2. モデルクラスで必要なモジュールのみを使⽤ • authenticate_user! • user_signed_in? • current_user c. テーブル分割⽅法の提案

Slide 33

Slide 33 text

ルーティング サインイン画⾯のビューをデフォルトで使⽤ 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 34

Slide 34 text

ルーティング サインイン画⾯表⽰⽤パスを作成するために、 emailとencrypted_passwordをもつ UserDatabaseAuthenticationモデルを devise_forの引数に指定する必要がある ※ devise_for : 指定されたモデルのためのルーティングを設定 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 35

Slide 35 text

ルーティング こんな感じ 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 36

Slide 36 text

アクション フォームからリクエストが送られるアクションの元実装 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 37

Slide 37 text

アクション sign_inメソッド:resourceとして渡されたオブジェクトのクラスが セッション開始を担っている時、セッション開始 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 38

Slide 38 text

アクション sign_inメソッド:resourceとして渡されたオブジェクトのクラスが セッション開始を担っている時、セッション開始 resourceはdevise_forに渡したUserDatabaseAuthenticationクラス のオブジェクトとなる 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 39

Slide 39 text

アクション sign_inメソッド:resourceとして渡されたオブジェクトのクラスが セッション開始を担っている時、セッション開始 resourceはdevise_forに渡したUserDatabaseAuthenticationクラス のオブジェクトとなる → Userクラスがセッション管理を担っていない 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 40

Slide 40 text

アクション ブロックを渡すとこの部分で実⾏してくれる 特定の処理を差し込める 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 41

Slide 41 text

アクション usersレコード由来のオブジェクトをsign_inメソッドに渡す処理を createメソッドのオーバーライド時に差し込む 3. 各種挙動に合わせて設定 c. テーブル分割⽅法の提案

Slide 42

Slide 42 text

以上の⼿順によって テーブル分割を⾏った上でサインイン機構を構築できた c. テーブル分割⽅法の提案

Slide 43

Slide 43 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 44

Slide 44 text

• Userクラスがスッキリして嬉しい気持ちになれた d. テーブル分割して実装してみた感想

Slide 45

Slide 45 text

• Userクラスがスッキリして嬉しい気持ちになれた • 認証⽅法の追加時に新テーブル作成に思考が向きやすくなった d. テーブル分割して実装してみた感想

Slide 46

Slide 46 text

• Userクラスがスッキリして嬉しい気持ちになれた • 認証⽅法の追加時に新テーブル作成に思考が向きやすくなった • とても難しい、、、今回の紹介は⼀番簡単な例 d. テーブル分割して実装してみた感想

Slide 47

Slide 47 text

• Userクラスがスッキリして嬉しい気持ちになれた • 認証⽅法の追加時に新テーブル作成に思考が向きやすくなった • とても難しい、、、今回の紹介は⼀番簡単な例 • 未来の実装時間を使⽤している気持ちにもなった d. テーブル分割して実装してみた感想

Slide 48

Slide 48 text

2. テーブル分割による柔軟な削除機構

Slide 49

Slide 49 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 50

Slide 50 text

a. ユーザーの削除時に考慮したいこと ユーザーの削除機構の仕様決定時には多くを考慮する必要がある • ⼀度削除されたユーザーの復元が可能か • ユーザー削除時に関連するデータは残すか • プライバシー情報を削除しなければならないか

Slide 51

Slide 51 text

これもテーブル分割で対応できるのでは? • ⼀度削除されたユーザーの復元が可能か • ユーザー削除時に関連するデータは残すか • プライバシー情報を削除しなければならないか a. ユーザーの削除時に考慮したいこと

Slide 52

Slide 52 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 53

Slide 53 text

b. 柔軟な削除機構を実現するための分割⽅法 管理⽅法 usersテーブルにactive_usersテーブルを関連付ける → usersテーブルのレコードがactive_usersを持つ時 そのユーザーはアプリケーションを使⽤可能

Slide 54

Slide 54 text

ユーザーの削除時 関連するactive_usersテーブルのレコードを削除する b. 柔軟な削除機構を実現するための分割⽅法

Slide 55

Slide 55 text

active_usersテーブルを採⽤した⽅法は柔軟な削除機構 以下を決定できる • ⼀度削除されたユーザーの復元が可能か • ユーザー削除時に関連するデータは残すか • プライバシー情報を削除しなければならないか b. 柔軟な削除機構を実現するための分割⽅法

Slide 56

Slide 56 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 57

Slide 57 text

削除するデータ、残すデータはこのように決定可能 例1:プライバシー情報 プライバシーであり、ユーザー退会時に⼀緒に削除したいデータ はactive_usersテーブルに配置 c. テーブル分割による削除機構の使⽤⽅法

Slide 58

Slide 58 text

削除するデータ、残すデータはこのように決定可能 例1:プライバシー情報 プライバシーであり、ユーザー退会時に⼀緒に削除したいデータ はactive_usersテーブルに配置 → active_usersのレコードと共にデータは削除される c. テーブル分割による削除機構の使⽤⽅法

Slide 59

Slide 59 text

削除するデータ、残すデータはこのように決定可能 例2:ユーザーに関連するデータを残す c. テーブル分割による削除機構の使⽤⽅法

Slide 60

Slide 60 text

削除するデータ、残すデータはこのように決定可能 例2:ユーザーに関連するデータを残す → active_usersのレコード削除時に関連データ(posts)も 削除するか柔軟に変更可能 c. テーブル分割による削除機構の使⽤⽅法

Slide 61

Slide 61 text

ユーザーを「⼀時的にロックする」などのように状態を追加した い場合には新しく状態⽤のテーブルを作成する ⽅向に思考が向く → クラスの肥⼤化を防ぐ c. テーブル分割による削除機構の使⽤⽅法

Slide 62

Slide 62 text

⽬次 1. Deviseにおけるusersテーブルの分割 a. Deviseとは b. Deviseをこんな⾵に使いたいな c. テーブル分割⽅法の提案 d. テーブルを分割して実装してみた感想 2. テーブル分割による柔軟な削除機構 a. ユーザーの削除時に考慮したいこと b. 柔軟な削除機構を実現するための分割⽅法 c. テーブル分割による削除機構の使⽤⽅法 3. まとめ

Slide 63

Slide 63 text

まとめ 1. Deviseのテーブルを分割するとUserクラスがスッキリする 2. テーブル分割によってユーザーの削除機構を柔軟にできる

Slide 64

Slide 64 text

ご清聴ありがとうございました