Rails で Devise と論理削除を両立する方法
はじめに
Rails で Devise と論理削除を両立する方法。
TL;DR
- 論理削除は jhawthorn/discard を利用
- 論理削除されたユーザーのログインを無効化
active_for_authentication?
をオーバーライド
- DB のユニーク制約を再設定する
validatable
と同等のバリデーションを自分で設定
目次
環境・条件
1 | $ cat /etc/os-release |
1 | mysql> status; |
詳細
論理削除の導入
参考: Railsで論理削除(soft delete)を実装する(discard gem利用) - Qiita
いくつか Gem があるが jhawthorn/discard を採用した。
- rubysherpas/paranoia
- 上記 Qiita にも書かれている新規導入には非推奨
- ActsAsParanoid/acts_as_paranoid
- paranoia のオリジナル。
destroy
などがオーバーライドされるので同様の理由で非推奨(という認識) - あと試したらレコード削除時になんかエラーになった(内容はメモし忘れた)
- paranoia のオリジナル。
README に従ってセットアップすれば OK。
Gemfile
に gem 'discard', '~> 1.2'
を追記。
1 | gem 'discard', '~> 1.2' |
bundle install
でインストール。
1 | $ bundle install |
論理削除用のカラムを追加。
1 | $ rails g migration add_discarded_at_to_users discarded_at:datetime:index |
モデルに include Discard::Model
を追加
1 | class User < Activerecord::Base |
user.discard
で論理削除したりが可能になる、以下は主要なもの。その他は Usage を参照。
1 | user.discard # 論理削除(discarded_at に現在日時が設定される) |
論理削除されたレコードをデフォルトで除外したい場合は、デフォルトスコープを設定する。
1 | class User < Activerecord::Base |
デフォルトスコープを設定した場合は、対象の抽出時に注意。
1 | User.all # 論理削除されていないレコード |
論理削除されたユーザーのログインを無効化
active_for_authentication?
をオーバーライドして、論理削除されていないユーザーのみがログイン可能に変更。(公式では super && !discarded?
だけど、 !discarded?
が二重否定みたいな感じがするので kept?
に変更した。)
1 | class User < Activerecord::Base |
DB ユニーク制約 再設定
MySQL 前提
参考:
email
に対してユニーク制約が設定されているので、Generated Column を追加して再設定する。MySQL と Generated Column については MySQL でユニーク制約と論理削除を同時に実現する方法 を参照。
1 | $ rails g migration reset_unique_constraint_to_users |
Qiita 記事では up
の中で execute "ALTER TABLE ...
としていたが、as
でも設定できる。
(Rails のバージョンによっては使えないかも)
1 | class ResetUniqueConstraintToUsers < ActiveRecord::Migration[6.0] |
バリデーション定義
Devise の設定とかソースコードを見た限りでは、validatable
の挙動変更はできないようなので、自前で定義する。
active_email
はレコード保存後に有効になるのでon: :update
に制限email_required?
を定義email
のユニーク検証はscoe: :discarded_at
を追加
- 類似の
active_email_required?
を追加 password_required?
を定義
1 | class User < Activerecord::Base |
lynndylanhurley/devise_token_auth を使う場合は、DeviseTokenAuth::Concerns::UserOmniauthCallbacks
相当も実装する必要がある
config/initializers/devise_token_auth.rb
を変更、コールバックを無効化。
1 | # By default we will use callbacks for single omniauth. |
バリデーションや関連メソッドを定義。
1 | class User < Activerecord::Base |
まとめ
- 論理削除は jhawthorn/discard を利用
- 論理削除されたユーザーのログインを無効化
active_for_authentication?
をオーバーライド
- DB のユニーク制約を再設定する
validatable
と同等のバリデーションを自分で設定
その他・メモ
後半(特に バリデーション定義)は書くのに力尽きて、なにかミスとかあるかもしれないので注意。
参考文献
- Railsで論理削除(soft delete)を実装する(discard gem利用) - Qiita
- MySQLのGenerated Columnsまとめ with Rails - Qiita
- jhawthorn/discard: 🃏🗑 Soft deletes for ActiveRecord done right
- heartcombo/devise: Flexible authentication solution for Rails with Warden.
- lynndylanhurley/devise_token_auth: Token based authentication for Rails JSON APIs. Designed to work with jToker and ng-token-auth.
- ruby on rails - Can’t disable validation of email in devise-auth-token - Stack Overflow
関連記事
- Rails で既存の DB を利用するアプリケーションの作成方法(DB 参照のみ)
- Rails で rambulance を使ってエラー種別ごとに動的にエラーページを切り替える
- Rails(devise)のユーザーを Firebase Authentication にエクスポートする
- Rails で high_voltage を使って静的ページを作成する
- Rails で favicon の設定
- Rails で Sitemap の作成、定期的な更新を行う
- JavaScript で URL のクエリパラメータを操作する方法
- jQuery Select2 で、初期値の設定と選択状態のクリア