Discordを使ってのログイン機能の作成
現在自作サービス作成中。 RailsでDiscordログインを実装する方法 #OmniAuth - Qiita
この記事を見ながらログイン機能を実装している。
その中で
models/user.rb
class User < ApplicationRecord def self.find_or_create_from_discord_info(discord_info) User.find_or_create_by(uid: discord_info.uid) do |user| user.update!( uid: discord_info.uid, name: discord_info.info.name, image: discord_info.info.image ) end end ...
のようにDiscord側から得た情報からユーザー情報を検索、該当なければ新規作成(find_or_create)している。
ただDiscord側のユーザー名やアバター画像は更新されることがある。
ログイン処理と更新処理は併せて処理したい。
find_or_create~にupateの処理を入れる?
models/users
def self.find_or_create_from_discord(auth_info) user = User.find_or_initialize_by(discord_user_id: auth_info.uid) user.update!( name: auth_info.info.name, avatar_url: auth_info.info.image ) end ...
find_or_create~内部処理を
- findで見つからないときはinitialize
- find_or_createで作成されたインスタンスのnameとavatar_urlを追加してupdate
で対応してみたが、なんとなくメソッド名と処理内容が合ってる気がしない。
updateが副作用っぽくなってしまう。
分けて定義する?
models/user.rb
def self.find_or_initialize_from_discord(auth_info) User.find_or_initialize_by(discord_user_id: auth_info.uid) end def update_from_discord(auth_info) update!( name: auth_info.info.name, avatar_url: auth_info.info.image ) end
責務は分離できているが、各処理を呼び出す際に
users/sessions_controller.rb
... def callback auth_info = request.env["omniauth.auth"] user = User.find_or_initialize_from_discord(auth_info) user.update_from_discord(auth_info) log_in user redirect_to root_path, notice: "ログインしました" end
のようにcontroller側で2つの処理を分けて書かないといけない。 これは1つにまとめたい。
呼び出しををまとめてみる
models/user.rb
class << self def sync_with_discord(auth_info) user = find_or_initialize_from_discord(auth_info) user.update_from_discord(auth_info) end private def find_or_initialize_from_discord(auth_info) find_or_initialize_by(discord_user_id: auth_info.uid) end end private def update_from_discord(auth_info) update!( name: auth_info.info.name, avatar_url: auth_info.info.image ) end
みたいにする。
呼び出しはsync_with_discordでまとめられたが、privateメソッドを複雑に作り過ぎている気もする。
最終的に
models/user.rb
def self.sync_with_discord(auth_info) user = User.find_or_initialize_by(discord_user_id: auth_info.uid) user.update!( name: auth_info.info.name, avatar_url: auth_info.info.image ) end
この形にまとめたが、sync_with_discordはDiscordと同期という訳になり、処理の内容がメソッド名から推測できるかちょっと不安である。
メソッド名がしっくり来ないときは、 「責務が大きすぎるのでは?」 と疑いたくなる。
ただ今回のように、
- ユーザー検索
- 新規作成
- 更新処理
を「ログイン時同期」という1ユースケースとして扱うなら、 ある程度まとめた方が使いやすいと判断した。
設計難しい。








