5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

sorceryを使用した“メールアドレス認証なし”の実装

Last updated at Posted at 2025-08-19

はじめに

初めましてこんにちは、ほげがめのてー(@sss__727)と申します。
現在、完全未経験からWebエンジニアを目指してオンラインプログラミングスクールRUNTEQにてRuby on Railsを学習しています。

この度、7月30日にミニゲームwebアプリ「KANIDIAN POKER」(以下、カニポカ)をリリースいたしました。

今回はそこで実装したログイン機能について記録していきます。

※記述に間違いがあればご教授いただきたいです!!!勉強させてください!!!

あくまで自分の個人開発での記録に過ぎませんので、参考になさる場合は十分に精査してからご自身でご判断ください!!!!

※sorceryは現在メンテナンス終わっているので使うことはオススメしません。

ログイン機能、devise or sorcery?

初めて個人開発でログイン機能を実装する際は、必ずと言っていいほどこの壁にぶち当たるのではないでしょうか。
そうです、gem 'devise' もしくは gem 'sorcery' のどちらを使うか?

結論から言うと私はsorceryを選択しました。
理由は二つのgemの機能の差にあります。

(機能の差はこちらで勉強させていただきました。)

この記事を読むに、diveseの方がカスタマイズ性は高いのでは?と思われますが、記事の結論にも書かれているように『開発するアプリケーションの内容によって、使用するGemを決めよう!』←これが全てでした。

今回アプリは、あくまで学習のアウトプットを目的にしたミニゲーム。
その上でコミュニティの仲間たちが手軽に楽しめる機能にしたい!という思いで開発を始めました。
そのため、よく話されていた「メールアドレスの登録はめんどくさい」「受講生レベルのアプリで個人情報を入れるのが躊躇われる」と言う現象は避けたい!
ならば名前とパスワードだけでユーザー登録できたら手軽で楽ちんじゃないか!と思い、その実装を目指します。
しかし、deviseでは様々なカスタム機能があるものの、全ての設定においてemailが必須でした。
……ダメやん。

そう言うわけでカニポカでは、sorceryを使用して二つ名・ニックネーム・パスワードの3つでユーザー登録とログインする方法を叶えました。

gem 'sorcery'でカスタムログイン機能を実装してみた

スクリーンショット 2025-08-19 9.47.50.png

前置きが長くなりました。始めましょう。(開発環境はdocker)

まずはGemfile。

Gemfile
gem 'sorcery'

# ▼コマンドで実行
docker compose run web bundle install
docker compose down
docker compose up
# (restartでいいみたいなんですけど一旦再起動させてます)

次に生成されたマイグレーションファイルの編集。
この際、デフォルトで記述されがちなemail欄は不要なので書きません。

db/migrate/XXXXXXXXXXXXXX_sorcery_core.rb
class SorceryCore < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :crypted_password
      t.string :salt
      t.string :first_name,               null: false   # 二つ名
      t.string :last_name,               null: false    # ニックネーム
   # (求)email欄は書かない!!!と言う確固たる意志。
   
      t.timestamps null: false
    end
  end
end

# マイグレーション
docker compose exec web rails db:migrate

モデルにもemailは必要ありません!!!書いてないからね!!!

app/models/user.rb
  validates :first_name, presence: true, uniqueness: true
  validates :last_name, presence: true
  validates :last_name, uniqueness: { scope: :first_name, message: "その組み合わせは既に使用されています" }
  validates :password, length: { minimum: 4 }, if: -> { new_record? || changes[:crypted_password] }
  validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] }
  validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] }

その代わりと言ってはなんですが、二つ名とニックネームが完全重複する場合のみバリデーションエラーが起きるよう設定してあります。

(例)

# パターン1: first_nameが同じでlast_nameが違う
User1: first_name: "進撃", last_name: "巨人"
User2: first_name: "進撃", last_name: "わたし"  # ← OK!

# パターン2: last_nameが同じでfirst_nameが違う
User1: first_name: "進撃", last_name: "巨人"
User3: first_name: "大きな", last_name: "巨人"  # ← OK!

# 完全に同じ組み合わせ
User1: first_name: "進撃", last_name: "巨人"
User4: first_name: "進撃", last_name: "巨人"  # ← NG!エラーになる

麦わらの一味がいるかもしれないですからね。(何の話?)

あとはこれに応じたコントローラーファイルとビューファイルを生成すれば完成です!

下記は一般的なCファイルです。(カニポカのCファイルではありません)

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    
    if @user.save
      redirect_to login_path, notice: 'ユーザー登録が完了しました!ログインしてください。'
    else
      flash.now[:alert] = 'ユーザー登録に失敗しました。'
      render :new, status: :unprocessable_entity
    end
  end

  def show
    @user = User.find(params[:id])
  end

  private

  def user_params                  # ↓emailは要りません!
    params.require(:user).permit(:first_name, :last_name, :password, :password_confirmation)
  end
end

こちらも一般的なVファイル。

app/views/users/new.html.erb
<div class="container">
  <div class="row justify-content-center">
    <div class="col-md-6">
      <div class="card">
          <h4 class="mb-0">新規ユーザー登録</h4>
            <div class="mb-3">
              <%= form.label :first_name, "二つ名", class: "form-label" %>
              <%= form.text_field :first_name, class: "form-control", placeholder: "例: 進撃" %>
            </div>

            <div class="mb-3">
              <%= form.label :last_name, "ニックネーム", class: "form-label" %>
              <%= form.text_field :last_name, class: "form-control", placeholder: "例: 巨人" %>
            </div>

            <div class="mb-3">
              <%= form.label :password, "パスワード", class: "form-label" %>
              <%= form.password_field :password, class: "form-control" %>
              <small class="form-text text-muted">4文字以上で入力してください</small>
            </div>

            <div class="mb-3">
              <%= form.label :password_confirmation, "パスワード確認", class: "form-label" %>
              <%= form.password_field :password_confirmation, class: "form-control" %>
            </div>

            <div class="d-grid">
              <%= form.submit "登録", class: "btn btn-primary" %>
            </div>
          <% end %>

          <div class="text-center mt-3">
            <%= link_to "ログインはこちら", login_path, class: "text-decoration-none" %>
          </div>
      </div>
    </div>
  </div>
</div>
        

完成です!

まとめ

sorceryは設計がシンプルな分、ユーザー登録の項目を選べるのが良いですね!
必要な項目だけをusersテーブルのマイグレーションファイルに記述し、MVCファイルにも必要な項目だけを記述すればOK!
そんなに複雑ではなかったです。

小話

実は、今回の実装はsorceryの方が向いているとわかったのはdeviseで多くのエラーと対峙したからでした。
何度やってもエラーが出るのでAIと原因を追求していたところ、deviseではemailが必須と言うことが判明。路線転換するためにdeviseのgemはアンインストールしたのですが、インストールした時に自動生成されてしまった関連ファイルを全て手動で消さなければならず、これが結構大変でした。
教訓としましては、「実装したい形が決まっているなら、それを実現するための機能をまず調べてからとりかかれ」と言う初歩的なことですね。
今回は「ようわからんけどみんな使ってるからdeviseだ〜!」と決めてしまったので。反省。

今後は下調べを終えてから開発に取り掛かることにします!
ご拝読いただきありがとうございました!


簡単ログイン機能が実装されたカニポカは以下です。
ご興味ありましたら、是非遊んでみてください。

ゲストユーザー情報
【金髪の校長】
二つ名:金髪
ニックネーム:校長
パスワード:1234

開発秘話はこちら

Twitterはこちら。

5
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?