1
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?

More than 1 year has passed since last update.

deviceを使わないでログイン認証機能を作ってみる

Posted at

※この記事はRails初学者向けです

deviceってなに?
railsのgemの一つで、ログイン認証機能が簡単に実装できる。
https://github.com/heartcombo/devise

gemは便利だけど、勉強のためにログイン認証周りの仕組みに興味があったので実装してみました。view周りの実装は今回の趣旨とは異なるため触れてません。

モデル・コントローラの準備

1. Userモデルを作成して、schemaファイルを修正

$ rails g model user name:string email:string encrypted_password:string
      invoke  active_record
      create    db/migrate/[timestamp]_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb
  • db/migrate/[timestamp]_create_users.rb に追記
class CreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.string :email, null: false
      t.string :encrypted_password, null: false

      t.timestamps
      t.index :email, unique: true
    end
  end
end

ログイン時にemailからユーザを特定するため、indexを貼って検索速度を上げ、
unique: trueとしてメールアドレスの一意性が保たれるようにします。

追記できたら以下を実行

$ rails db:migrate
== [timestamp] CreateUsers: migrating ==================================
-- create_table(:users)
   -> 0.0420s
== [timestamp] CreateUsers: migrated (0.0421s) =========================
$ rails db:migrate:redo
== [timestamp] CreateUsers: reverting ==================================
-- drop_table(:users)
   -> 0.0083s
== [timestamp] CreateUsers: reverted (0.0176s) =========================

== [timestamp] CreateUsers: migrating ==================================
-- create_table(:users)
   -> 0.0140s
== [timestamp] CreateUsers: migrated (0.0141s) =========================

マイグレーションは1つ前の状態に戻せることを担保できていることが大切なので
rails db:migrate:redoを流して確認する癖をつけましょう。

2. Userの新規登録機能の実装

Usersコントローラを作成

$ rails g controller Users new create
      create  app/controllers/users_controller.rb
       route  get 'users/new'
              get 'users/create'
      (省略)

ルーティングを修正
  • config/routes.rbに追記
Rails.application.routes.draw do
  (省略)
  resources :users, only: [:new, :create] 
end

Userモデルにバリデーションやコールバックを実装

  • app/models/user.rbに追記
class User < ApplicationRecord
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

  attribute :password, :string

  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  validates :encrypted_password, presence: true, length: { is: 128 }
  validates :password, presence: true, length: { minimum: 6 }

  after_initialize do |user|
    user.encrypted_password = Digest::SHA512.hexdigest(user.password) if user.password
  end

  before_save :downcase_email!

  private

  def downcase_email!
    email.downcase!
  end
end

after_initializeコールバックの中で、ユーザ登録される際、view側からpasswordとして受け取り、それをハッシュ化(データを不規則な文字列に変換する手法)してencrypted_passwordに渡しています。

http://localhost:3000/users/new にアクセスし、
ユーザが登録できることを確認しましょう。
スクリーンショット 2022-08-28 9.10.23.png
スクリーンショット 2022-08-28 9.14.03.png

$ rails c
Loading development environment (Rails 7.0.3.1)
irb(main):001:0> User.all
  User Load (8.4ms)  SELECT `users`.* FROM `users`
=>
[#<User:0x000000011668b598
  id: 1,
  name: "test_user",
  email: "test@example.com",
  encrypted_password: "[FILTERED]",
  (省略)

登録できていそうですね。
次はログインログアウトの機能を追加していきます。

3. ログイン・ログアウト機能の実装

sessionsコントローラを作成します。

$ rails g controller Sessions new create destroy
      create  app/controllers/sessions_controller.rb
       route  get 'sessions/new'
              get 'sessions/create'
              get 'sessions/destroy'
      (省略)

ルーティングを修正
  • config/routes.rbに追記
Rails.application.routes.draw do
  (省略)
  resources :users, only: [:new, :create] 
  get :login, to: 'sessions#new'
  post :login, to: 'sessions#create'
  delete :logout, to: 'sessions#destroy'
end

pathを分かりやすくするために loginlogoutに設定しました。
続いてコントローラの中身を実装していきたいのですが、その前にControllerやviewで使いたいので、ヘルパーを準備しておきます。

  • app/helpers/sessions_helper.rb に追記
module SessionsHelper
  def log_in(user)
    session[:user_id] = user.id
  end

  def current_user
    @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
  end

  def log_out
    reset_session
  end
end

sessions_helperをapplication_controllerでincludeしておきます。

  • app/controllers/application_controller.rbに追記
class ApplicationController < ActionController::Base
  include SessionsHelper
end
  • app/controllers/sessions_controller.rbに追記
class SessionsController < ApplicationController
  def new
  end

  def create
    user = User.find_by(email: params[:email].downcase)
    if user && Digest::SHA512.hexdigest(params[:password]) == user.encrypted_password
      login
      flash[:success] = 'ログインが成功しました'
      redirect_to root_path
    else
      flash[:danger] = 'メールアドレス・またはパスワードが正しくありません'
      render :new
    end
  end

  def destroy
    reset_session
    redirect_to root_path
  end
end

ここでやってるのは、先にUserモデルからparams[:email]に一致するユーザを検索。ユーザが見つかり、かつuser.encrypted_passwordparams[:password]をハッシュ化した値が一致すればsession[:user_id]user_idを入れています。

http://localhost:3000/login にアクセスしログインしてみましょう。
スクリーンショット 2022-08-28 9.28.55.png
スクリーンショット 2022-08-28 9.29.50.png

これでログインできました。
ログイン状態ならログアウトボタン、ログアウト状態ならユーザ登録とログインボタンを表示させてみましょう。
今回はテスト用にヘッダーに表示させています。

  • app/views/layouts/_header.html.erbに追記
<header class="navbar navbar-fixed-top">
 <div class="container">
   <%= link_to(image_tag("", :alt => ""), root_url, id: 'logo') %>
   <nav>
     <ul class="nav navbar-nav navbar-left">
       <% if current_user %>
        <li class="navbar-item"><%= button_to "ログアウト", logout_path, method: :delete %></li>
      <% else %>
        <li class="navbar-item"><%= link_to "ユーザー登録", new_user_path %></li>
        <li class="navbar-item"><%= link_to "ログイン", login_path %></li>
      <% end %>
     </ul>
   </nav>
 </div>
</header>
  • ログイン状態
    スクリーンショット 2022-08-28 10.08.41.png

  • ログアウト状態
    スクリーンショット 2022-08-28 10.10.00.png

うまく実装できていそうです。
current_userでログイン状態が分かるようになったので、別の機能の実装する際も、ログインしていなければリダイレクトさせるようなコールバックにも使えますね。

gemを使わずにログイン周りの機能を実装できました。
これで以上になります!

1
0
0

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
1
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?