オープンソースプロジェクトにおける退会処理のパターン
Railsのプロジェクトから調査しました。購入履歴を消せないなどの理由でUserテーブルに状態をもたせて管理しているようなものをみたかったのですがなかったです。もしそういうものをご存知の方がいればコメント欄で教えていただきたいです
Redmine
コントローラーからは User.destroy
を呼び出し、 before_destroy
で remove_references_before_destroy
(redmine/user.rb at master · redmine/redmine)を呼んでいる。 remove_references_before_destroy
では、当該ユーザーの関連レコードをすべて anonymous
ユーザーに紐付けたり、不要なレコードを削除したりしている。
ユーザーは完全に削除しつつ、そのユーザーが作成した投稿などは消えたら困るので1人の匿名ユーザーに紐付けするという方針
# Removes references that are not handled by associations
# Things that are not deleted are reassociated with the anonymous user
def remove_references_before_destroy
return if self.id.nil?
substitute = User.anonymous
Attachment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
Comment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
Issue.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
Issue.where(['assigned_to_id = ?', id]).update_all('assigned_to_id = NULL')
Journal.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
JournalDetail.
where(["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]).
update_all(['old_value = ?', substitute.id.to_s])
JournalDetail.
where(["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]).
update_all(['value = ?', substitute.id.to_s])
Message.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
News.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
# Remove private queries and keep public ones
::Query.where('user_id = ? AND visibility = ?', id, ::Query::VISIBILITY_PRIVATE).delete_all
::Query.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
TimeEntry.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
Token.where('user_id = ?', id).delete_all
Watcher.where('user_id = ?', id).delete_all
WikiContent.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
WikiContentVersion.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
user_custom_field_ids = CustomField.where(field_format: 'user').ids
if user_custom_field_ids.any?
CustomValue.where(custom_field_id: user_custom_field_ids, value: self.id.to_s).delete_all
end
end
Discourse(掲示板)
discourse/discourse: A platform for community discussion. Free, open, simple.
UserDestroyer
(URL)にて処理。
- 関連テーブルの削除
- 特定の
user_id
をもったログ情報は、記録のためにuser_idを備考欄にコピーしてから、user_idを消すというような処理もあった
- 特定の
- 掲示板への投稿はシステムユーザーに置き換え
- ログイン情報の削除の際は、ログイン用のメールアドレスだけは
ScreenedEmail
というモデルで保存している
ScreenedEmail
はBANしたアカウントの管理にも使われているようだった。
def destroy
@user = fetch_user_from_params
guardian.ensure_can_delete_user!(@user)
UserDestroyer.new(current_user).destroy(@user, delete_posts: true, context: params[:context])
render json: success_json
end
ScreenedEmail
というテーブルはこのような感じ。BANしたアカウントなどもこちらで管理しているようだ
class AddIpAddressToScreeningTables < ActiveRecord::Migration[4.2]
def change
add_column :screened_emails, :ip_address, :inet
add_column :screened_urls, :ip_address, :inet
end
end
Gitlab
gitlabhq/destroy_service.rb at 76365117183054e95bbb2f3a6392ac333628eacf · gitlabhq/gitlabhq
-
global ghost user
というものに関連レコードの所有者を置き換える - 関連レコードの削除
- Railsは関連レコードを削除するとき、すべてメモリに読み込んでしまうので、バッチで削除するという工夫をしている
Mastodon
mastodon/delete_account_service.rb at 3a103cd317fd56aca27fca01e03647df44e3ffd2 · mastodon/mastodon
- 関連レコードの削除
- アクティビティーを記録
- アンフォロー
その他にも私は詳しくないのだが、他のMastodonとの関連の処理がいろいろされているようだった。
def destroy_account!
current_account.suspend!(origin: :local, block_email: false)
AccountDeletionWorker.perform_async(current_user.account_id)
sign_out
end
Discussion