sorceryで認証機能を追加してみる

#Sorceryとは？
Sorceryは、ユーザ認証機能を簡単に実装できるライブラリ

https://github.com/Sorcery/sorcery/wiki/Simple-Password-Authentication
#パスワード認証機能
**今回は基本的な機能であるパスワード認証の実装**
・ユーザー登録機能
・ログイン機能
・ログアウト機能

#Sorceryの導入
```
gem 'sorcery'
```

#Userモデルを作成
<font color="DeepPink">bundle exec rails g sorcery:install</font>を実行し、Userモデルとデータベースのmigrationを生成します。

今回usersテーブルにはfull_nameカラムを追加そしてstring型と必須項目を追加。
[![Image from Gyazo](https://i.gyazo.com/70c46698828ebf3151a1ba8806022520.png)](https://gyazo.com/70c46698828ebf3151a1ba8806022520)

#User登録機能を実装
Userモデルをベースに実装していきます。
**モデルの実装**
はじめに、Userモデルのフィールドである、

・email
・password
・password_confirmation
・full_name
に対するバリデーションを実装します。

```
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, precense: true
  validates :full_name, presence: true
end
```

#コントローラーの実装
bundle exec rails g controller new createを実行
次にルーティングを定義しておきます。

```routes.rb
Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  resources :users, only: [:new, :create]
end
```
コントローラーの中身はこの様な感じです

```users_controller.rb
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to welcome_path #createアクションでUser登録が成功した際にリダイレクト先としてwelcome_pathを指定しています
    else
      render :new
    end
  end

  private

  def user_params #createで送られてきた値をparams.require
    params.require(:user).permit(
      :email,
      :password,
      :password_confirmation,
      :full_name
    )
  end
end
```
welcome_pathはログイン画面へのパスのためこのままだとroutingエラーになるので後ほどログイン画面へのルーティングを記述します。

#Viewの実装
Form_withを使用します。
Bootstrapを使用。

```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 :full_name %> 
           <%= f.last_name :full_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>

```
form_withでつまづく可能性があるので参考になるサイトを載せます。

https://pikawaka.com/rails/form_with

https://qiita.com/hayulu/items/5bf26656d7433d406ede

#ログイン画面へのルーティング
ログイン画面はSessionControllerというコントローラーを作成しなければいけません？

```
$bundle exec rails g controller session new create destroy
```

```routes.rb
get 'welcome', to: 'session#new'
post 'login', to: 'session#create'
logout 'logout', to: 'session#destory'
```
これでwelcome_pathへるぱが作成され、ログイン画面へのルーティングが可能となりユーザ登録機能が実装できました。
しかし、ここまでの実装ではsorceryの提供する機能は使っていません。
次からsorceryを使った認証機能を実装していきます。
#認証機能を実装
ここでは、次のようなシナリオを考えてみます。

認証が必要なページへアクセスした場合
・認証済みの場合
要求されたページを応答する。
・認証されていない場合
ログインページを応答する。
・認証が不要なページへアクセスした場合
要求されたページを応答する。

これを実装するにはルーティングに認証が必要となるページへルーティングを追加します。HomeControllerのindexアクションが該当するものとして、このコントローラをbundle exec rails g controller home indexを実行して作成します。また、home#indexをルートパスとして定義するため、config/routes.rbに以下を追加します

```
root to: 'home#index'
```
この時点では認証なしでどこのページでもアクセスできる状態です。

#認証済み判定処理
認証が必要なページがリクエストされた場合、認証済みか否かを判定する必要があります。 これを実現するには、Sorceryが提供する**require_login**メソッドをbefore_actionに指定します。 これは、ApplicationControllerに書きます。 また、require_loginをbefore_actionに指定するにあたり、認証されていない場合の処理も合わせて実装する必要があります。 デフォルトでは、Sorceryは、**not_authenticated**というメソッドを実行するため、この名前で実装します。ここでは、認証されていない場合は、ログインページへリダイレクトする実装としています。

https://qiita.com/aiandrox/items/65317517954d8d44d957

```application_controller.rb
before_action :require_login

protected

def not_authenticated 
  redirect_to welcome_path
end
```

ですがこのままではログインページ自体もbefore_actionが動作してしまうため認証済み判定が不必要なControllerではbefore_actionをスキップする必要があります。例えば以下のコードはSession_controllerの実装です

```session_controller.rb
skip_before_action :reqire_login, except: [:destroy]
```