6
4

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 3 years have passed since last update.

Rails ログイン機能 [sorcery] 解説

Last updated at Posted at 2021-10-22

#Rails ログイン機能実装手順 (自分用)

・sorceryをGemfileに追加する

Gemfile
gem ‘sorcery’

・次にbundle install

ターミナル
$ bundle install

・sorceryに追加されたジェネレータを実行して、アプリの構築をする

ターミナル
$ rails g sorcery:install

・マイグレーションファイルとuserモデルが作成される


ターミナル
$ rails db:migrate

・で導入完了

#sorcery:installで生成したUserモデルにバリデーションを追加
・Model
以下のようにバリテーションを追加

app/models/user.rb
class User < ActiveRecord::Base
  authenticates_with_sorcery!
  
  validates :password, length: { minimum: 3 }, 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] }

  validates :email, uniqueness: true, presence: true
  validates :first_name, presence: true, length: { maximum: 255 }
  validates :last_name, presence: true, length: { maximum: 255 }
end

#sorcery:installで生成したマイグレーションファイルに必要なカラムを追加する
・ここではlast_nameとfirst_nammeを追加

db/migrateXXXXXXXXXXXXXXX_sorcery_core.rb
class SorceryCore < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :email,            null: false
      t.string :crypted_password
      t.string :salt
      t.string :last_name, null: false #null: falseは空欄入力では名前とは認めないという意味
      t.string :first_name, null: false

      t.timestamps                null: false
    end

    add_index :users, :email, unique: true
  end
end

・マイグレートする

ターミナル
$ rails db:migrate

#ユーザーの新規登録画面を作成(scaffoldを使ってuserコントローラーを作成。)

ターミナル
$ rails g scaffold_controller user email:string crypted_password:string salt:string first_name:string last_name:string

・usersファイルにある、crypted_password、saltの部分はビューに表示しないので削除してpasswordとpassword_confirmationを代わりに入れる。(GitHubのREADMEにはこの手順で書いてあるが、最初から「rails g scaffold_controller user email:string password:string password_confirmation:string first_name:string last_name:string」で実行してもいいと思う。)


・Controller

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def new
    @user = User.new #(新規登録で作ったデータを@userに代入する)
  end

  def create
    @user = User.new(user_params)#(postメソッドでUser.newからのデータが送られてきている)新規登録で作ったデータに(user_params)という引数をつけて@userに代入する  
    if @user.save#訳:@userが保存できたら
      redirect_to login_path #(ログイン出来たら「user_sessionsのnew」に飛ぶ(redirect_to)ようになる。*「user_sessionsについては後に説明)
    else#訳:@userが保存できなかったら
      render :new #(ログイン出来なければ、usersのnewに戻る(render)) 
    end
  end

  private

  def user_params
        params.require(:user).permit(:email, :password, :password_confirmation, :first_name, :last_name, :salt)
#Task.newで作られたparams[:user]からemail、password、password_confirmation、first_name,last_nameだけを受け取るようにする。
   end
end

・app/views/users/new.html.erbの編集

app/views/users/new.html.erb
<div class="container">
  <div class="row">
    <div class="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
      <h1>ユーザー登録</h1>
      <%= form_with model: @user, local: true do |f| %>
        <div class="form-group">
          <%= f.label :last_name %>
          <%= f.text_field :last_name, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :first_name %>
          <%= f.text_field :first_name, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :email %>
          <%= f.email_field :email, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :password %>
          <%= f.password_field :password, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :password_confirmation %>
          <%= f.password_field :password_confirmation, class: 'form-control' %>
        </div>
        <%= f.submit '登録', class: 'btn btn-primary' %>
      <% end %>
      <div class='text-center'>
        <%= link_to 'ログインページへ', login_path %>
      </div>
    </div>
  </div>
</div>

・新規登録の画面では、登録するデータをデータベースに保存する必要があるので「form_with model」を使用している。


・ルーティングを定義する

onfig/routes.rb
  get 'login', to: 'user_sessions#new' #login_pathが使えるようになり、login_pathが使われるとログイン画面('user_sessions#new')に移動する
  post 'login', to: 'user_sessions#create' #login_path('user_sessions#new')からのデータを'user_sessions#create'へ受け取って、データベースに保存
  delete 'logout', to: 'user_sessions#destroy' #logout_pathが使えるようになる。削除処理を行う。

  resources :users, only: %i[new create]#usersではnewとcreateしか使わないのでonlyで指定している

#ログイン画面を作成

ターミナル
% rails g controller UserSessions new create destroy

・ログインに必要なuser_sessions_controllerを作成


・コントローラの親にあたる、application_controllerに共通のメソッドを追加する

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :require_login

  private

  def not_authenticated
    redirect_to login_path, danger: "ログインしてください"
  end
end

・before_actionはコントローラー内の全てのアクションが実行される前に、その後に続くメソッド(ここではrequire_login)が実行される。
・require_loginメソッドはloginしているかどうかを検証するメソッド。loginできれば、次に進もうとしていたページにリダイレクトできる。loginできなければ「not_authenticated」メソッドが実行される。
・not_authenticatedメソッドは、require_loginでlogin出来なかった場合に実行されるメソッド。ここでは「redirect_to login_path」となっているのでログイン画面('user_sessions#new')にリダイレクトされる。


・user_sessions_controllerの編集

app/controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
  skip_before_action :require_login, only: %i[create new] #下記で説明
  def new; end

  def create
    @user = login(params[:email], params[:password]) #emailとpasswordが一致していれば@userにデータが代入される(loginメソッドで検証を行なっている)
    if @user #訳:loginメソッドで検証が一致して、@userにデータだ代入されたら
      redirect_back_or_to root_path #ログインしたらroot_path(root toなどで指定したページ)にリダイレクトする。
    else
      render :new #ログイン出来なかったら、ログインページ('user_sessions#new')にリダイレクトされる
    end
  end
end

#####skip_before_action :require_login, only: %i[create new]の説明
・skip_before_actionでbefore_actionをスキップするという意味になる。つまりここでは、[create new]はログインする際に訪れないといけないページなので、ここで「before_action :require_login」が実行されるとそもそもログイン出来なくなる。なので、「only: %i[create new]」でこのページはログインしているかの検証はしないということになる。


・ログインフォーム作成

app/views/user_sessions/new.html.erb
<div class="container">
  <div class="row">
    <div class=" col-md-10 offset-md-1 col-lg-8 offset-lg-2">
      <h1>ログイン</h1>
      <%= form_with url: login_path, local: true do |f| %>
        <div class="form-group">
          <%= f.label :email %>
          <%= f.text_field :email, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :password %>
          <%= f.password_field :password, class: 'form-control' %>
        </div>
        <div class="actions">
          <%= f.submit 'ログイン', class: 'btn btn-primary' %>
        </div>
      <% end %>
      <div class='text-center'>
        <%= link_to '登録ページへ', new_user_path %>
        <a href="#">パスワードをお忘れの方はこちら</a>
      </div>
    </div>
  </div>
</div>

・ログインページでは、新規登録と違いデータベースに保存する必要がなく、パスワードとメールアドレスが一致しているかのデータ検証が目的なので「form_with url」を使用している。


#ログインしている時としていない時のトップページを分ける(logged_in?メソッド)
・logged_in?メソッドはsorceryで使えるようになるメソッドで、ログインしているかどうかを判断するメソッド。

app/views/layouts/application.html.erb
  <body>
    <% if logged_in? %>
      <%= render 'shared/header' %>#ログインしている時のrender先
    <% else %>
      <%= render 'shared/before_login_header' %>#ログインしていない時のrender先
    <% end %>
    <%= yield %>
    <%= render 'shared/footer' %>
  </body>

#ログイン機能をヘッダーに追加する
※Bootstrapで全体的なレイアウトやヘッダーのプルダウンが機能している

app/views/shared/_before_login_header.html.erb
<header>
  <nav class="navbar navbar-expand-lg navigation navbar-light bg-light">

    <button class='navbar-toggler' data-toggle='collapse' data-target='#navbarSupportedContent' aria-controls='navbarSupportedContent' aria-expanded='false' aria-label='Toggle navigation'>
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto main-nav align-items-center">
        <li class="nav-item">
          <%= link_to 'ログイン', 'login_path', class: 'nav-link' %> #リンク先をlogin_pathまたは、’login’にする
        </li>
      </ul>
    </div>
  </nav>
</header>

・リンク先を「login_path」にすることで、コントローラーで設定したように、ログイン画面に飛ぶことができる。
#ログアウト機能をヘッダーに追加する
※Bootstrapで全体的なレイアウトやヘッダーのプルダウンが機能している

app/controllers/user_sessions_controller.rb
def destroy
    logout
    redirect_to root_path #リダイレクト先をログイン画面に指定する
  end
app/views/shared/header.html.erb
 <%= link_to 'ログアウト', logout_path, class: 'dropdown-item', method: :delete %>

・リンク先をログアウトに指定し、deleteメソッドを追加

6
4
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
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?