【Ruby on  Rails】 devise 新規登録 ログイン 実装 手順

#はじめに
WEBサイトを作成する上で、ユーザーの登録からログイン・ログアウトまでできるサイトがほとんどだと思います。今回は、deviseを使って実装していきましょう。
##目次

+ サーバーが起動していたら停止する
+ Gem(devise)をインストールする
+ deviseの設定ファイルを作成する
+ Userモデルを作成する
+ 必要なビューの知識
+ パスの調べ方(prefix)
+ サインイン(user_signed_in?)
+ リダイレクトをコントローラーに実装する
+ 新規登録・ログイン画面を実装する(view)
+ usersテーブルに名前を保存できるようにする
+ 命名規則(スネークケース・キャメルケース)
+ 新規登録画面に名前フォームを追加する
+ ストロングパラメータを編集する(devise用)


####サーバーが起動していたら停止する
control + Cキー　を同時押ししましょう。
####Gem(devise)をインストールする
まずはじめにGemfileに以下を追記しましょう。

```:Gemfile
gem 'devise'
```
続いて　bundle install　を実行します。

```:ターミナル
$ bundle install
```
####deviseの設定ファイルを作成する

```:ターミナル
$ rails g devise:install
```
deviseに必要な2つのファイルが生成されました。

```:ターミナル
create  config/initializers/devise.rb
create  config/locales/devise.en.yml
```
ユーザーを登録するためには、何が必要でしょうか？そうですアカウントを保存するためのデータベースが必要ですね。まずは、モデルを作っていきましょう。
####Userモデルを作成する
ここで注意しなければいけないのがdevise専用のコマンドを実行することです。
以下を実行してUserモデルを生成します。

```:ターミナル
$ rails g devise user
```
必要なファイルが生成されました。
モデルを生成しただけでは、テーブルは作成されていませんね。
以下のコマンドを実行してテーブルを作成しましょう。

```
$ rake db:migrate
```
これでテーブルができました。
##必要なビューの知識
ここで、少しビューの知識についても触れておきます。なぜならログイン機能は、ログインされている時とログアウトしている時のナビゲーションの表示が異なる場合がほとんどだからです。
####表示タグ(<% %>)

```
<% post.text %>
```
ビューに表示されない

```
<%= post.text %>
```
ビューに表示される
####リンク(link_to)
HTMLだとaタグと同様だと思ってください。html.erbファイルでは、以下のように記述します。

```
<%= link_to 'ビューに表示される文字', 'パス' %>
```
クラスをつける場合は以下のようになります。

```
<%= link_to 'ビューに表示される文字', 'パス', class: 'クラス名' %>
```
####パスの調べ方(prefix)
Railsでは、パスをターミナルで調べる方法があります。

```:ターミナル
$ rake routes
```
実行後

```:ターミナル
posts_new GET    /posts/new(.:format)   posts#new
```
現在、使えるパスがズラーッと表示されたかと思いますが、

```:ターミナル
posts_new
```
これが、リンクタグなどで使えるパスになります。ただ、これを追記するだけではエラーになってしまいます。例えば、新規投稿画面へのリンクをブラウザに表示する場合には以下を参考にしてください。

```:html.erb
<%= link_to '新規投稿画面へ移動します', 'posts_new_path' %>
```
このように調べたパスのあとに _path　とつけるだけです。
####サインイン(user_signed_in?)
ログイン・ログアウト機能で必要なメソッドになります。使い方は簡単です。

```:html.erb
<% if user_signed_in? %>
    # ユーザーがサインインしている場合に実行する処理
<% end %>
```
サインアウトしている場合は、なにを追記すればいいでしょうか？ヒントは条件分岐です。

```:html.erb
<% if user_signed_in? %>
    # ユーザーがログインしている場合に実行する処理
<% else %>
　　# ユーザーがログアウトしている場合に実行する処理
<% end %>
```
ログイン・ログアウトの機能は全てのページに表示させておく必要があるので、共通のビューに関する記述は　app/views/layouts/application.html.erb　でしたね。

```php3:application.html.erb
<header class="header">
      <div class="header__bar row">
        <h1 class="grid-6"><a href="/">サイトタイトル</a></h1>

        <% if user_signed_in? %>
          <div class="user_nav grid-6">
            <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
            <a class="post" href="/posts/new">投稿する</a>
          </div>

        <% else %>
          <div class="grid-6">
            <%= link_to "ログイン", new_user_session_path, class: 'post' %>
            <%= link_to "新規登録", new_user_registration_path, class: 'post' %>
          </div>

        <% end %>
      </div>
</header>
```
上記は、あくまで参考ですので、レイアウトは変更してください。これで、ナビゲーションにログイン・ログアウトのリンクをつけることができました。
##リダイレクトをコントローラーに実装する
ログイン・ログアウト機能まで実装することができました。ただ、一つ問題点があります。それは、新規投稿のパスに直接アクセスできてしまいます。それができないようにログインしてない場合には強制的にログイン画面に移動するようにリダイレクトという機能を実装していきます。
####リダイレクトする(redirect_to)
Railsでは、アクション内の処理が終了すると"自動的"にアクション名と同名のビューが表示されますので、アクションの処理が終わり強制的に別のアクションを実行する場合などに使います。

```
redirect_to action: :index
               キー: :バリュー
```
※indexアクションにリダイレクトするという記述になります。
####指定のアクションを優先して実行する(before_action)

```:pusts_controller.rb
    before_action :manji, except: :index
    # indexアクション以外が実行される前にmanjiメソッドが実行される。

    def index
      @posts = Post.all
    end

    private
    def manji
    end
```
それでは、ログインしていないときに新規投稿しようとすると、indexアクションに強制リダイレクトするようにmanjiアクションに記述していきます。

```:pusts_controller.rb
private
def manji
　　redirect_to action: :index unless user_signed_in?
end
```
unlessという見慣れないコードがでてきました。
####unless文
簡単にいうとif文と真逆の処理をします。
if文は　もしも評価が真(true)であれば○○する　でしたね。
unless文は　もしも評価が偽(false)であれば○○する　という意味になります。

```
unless 条件式
    # 条件式が偽(false)のときに実行する処理
else
    # 条件式が真(true)のときに実行する処理
end
```
####
それでは、コントローラーを以下に編集します。

```:pusts_controller.rb
class PostsController < ApplicationController

    before_action :manji, except: :index

    def index
      @posts = Post.page(params[:page]).per(5).order("created_at DESC")
    end

    def new
    end

    def create
      post.create(post_params)
    end

    private
    def post_params
      params.permit(:name, :text)
    end

    def manji
      redirect_to action: :index unless user_signed_in?
    end
  end
```
これで、ログイン前に新規投稿ができるという問題が解決しました。
##ログイン・新規登録画面を実装する(view)
deviseでログイン機能を実装すると、ログイン・新規登録画面は自動的に生成されますがビューファイルとしては生成されていません。ブラウザで、新規登録・ログインに進むと表示されますがこれはGem(devise)中のビューを読みこんでいるためです。
そこで、ログイン・新規登録画面のビューを変更するには以下のコマンドで、devise用のviewファイルを生成する必要があります。

```:ターミナル
$ rails g devise:views
```
実行すると　app/views/devise　にファイルが生成されました。
####新規登録画面のviewを変更する
registrationsとは英語という意味になります。翻訳するとなんとなくパスも理解できると思います。

```php:app/views/devise/registrations/new.html.erb
<div class="contents row">
    <h2>Sign up</h2>
    <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
      <%= devise_error_messages! %>

      <div class="field">
        <%= f.label :email %><br />
        <%= f.email_field :email %>
      </div>


      <div class="field">
        <%= f.label :password %>
        <% if @validatable %>
        <em>(<%= @minimum_password_length %> characters minimum)</em>
        <% end %><br />
        <%= f.password_field :password, autocomplete: "off" %>
      </div>

      <div class="field">
        <%= f.label :password_confirmation %><br />
        <%= f.password_field :password_confirmation, autocomplete: "off" %>
      </div>

      <div class="actions">
        <%= f.submit "Sign up" %>
      </div>
    <% end %>
  </div>
```
####ログイン画面のviewを変更する

```php:app/views/devise/sessions/new.html.erb
<div class="contents row">
    <h2>Log in</h2>

    <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>

      <div class="field">
        <%= f.label :email %><br />
        <%= f.email_field :email, autofocus: true %>
      </div>

      <div class="field">
        <%= f.label :password %><br />
        <%= f.password_field :password, autocomplete: "off" %>
      </div>

      <% if devise_mapping.rememberable? -%>
        <div class="field">
          <%= f.label :remember_me %><br />
          <%= f.check_box :remember_me %>
        </div>
      <% end -%>

      <div class="actions">
        <%= f.submit "Log in" %>
      </div>
    <% end %>
  </div>
```
CSSやbootstrapのレイアウトについては、割愛しております。
####ブラウザでログイン・新規登録画面を確認する
これで、ユーザー登録・ログインの準備ができました。今回は、登録するユーザーの名前も保存するようにします。ではここで、データの保存先(usersテーブル)確認してみます。
usersテーブルには「idカラム」「emailカラム」「passwordカラム」しか存在していないので、名前にあたる「nameカラム」を追加していきましょう。
##usersテーブルに名前を保存できるようにカラムを追加する
名前を追加するためにusersテーブルにnameカラムを追加していきましょう。ここには、新規登録の時に登録する名前を保存できるようにします。
####マイグレーションファイルを作成してカラムを追加する
ファイルを生成するコマンドは "rails g" でしたね。

```:ターミナル
$ rails g migration AddNameToUsers name:string
```
解説

```:ターミナル
$ rails g migration AddカラムToテーブル カラム:データの型
```
以下のコマンドを実行してテーブルを生成します。

```:ターミナル
$ rake db:migrate
```
これで、usersテーブルにnameカラムを追加することができました。
もし間違ったカラム名で追加してしまった場合などは一つ前に戻るコマンドを実行しましょう。

```:ターミナル
$ rake db:rollback
```
を実行したあとできてしまったマイグレーションファイルを消しましょう。
####migrationファイルがどのような状態なのか確認するコマンド

```
$ rake db:migrate:status
```

```
Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190420082207  Create tweets
   down   20190421185018  Devise create users
```
upなら実行されていてdownは未実行という意味
####マイグレーションカラムの追加(add_column)
まず、マイグレーションファイルの生成をします。

```:ターミナル
$ rails g migration AddRateToテーブル名
```
マイグレーションファイルに追記します。

```:マイグレーションファイル例
class AddPriceToBooks < ActiveRecord::Migration[5.2]
  def change
    add_column :テーブル, :カラム, :型
    add_column :テーブル, :カラム, :型
  end
end
```
####マイグレーションカラムの削除(remove_column)

```:マイグレーションファイル
remove_column :テーブル名, :カラム名, :カラムの型
```
###命名規則
先程、マイグレーションファイルを生成する時にターミナルに記述した命名規則2つを紹介します。
####キャメルケース
単語の頭文字を大文字で繋げる

```
AddNameToUsers name:string
```
####スネークケース
_で区切る

```
add_name_to_users name:string
```
##新規登録画面に名前フォームを追加する

```:app/views/devise/sessions/new.html.erb
<div class="contents row">
    <h2>Sign up</h2>

    <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
      <%= render "devise/shared/error_messages", resource: resource %>

      <!-- ここから -->
      <div class="field">
        <%= f.label :name %> <em>(6 characters maximum)</em><br />
        <%= f.text_field :name, autofocus: true, maxlength: "8" %>
      </div>
      <!-- ここまでを追記します -->

      <div class="field">
        <%= f.label :email %><br />
        <%= f.email_field :email %>
      </div>

      <div class="field">
        <%= f.label :password %>
        <% if @validatable %>
        <em>(<%= @minimum_password_length %> characters minimum)</em>
        <% end %><br />
        <%= f.password_field :password, autocomplete: "new-password" %>
      </div>

      <div class="field">
        <%= f.label :password_confirmation %><br />
        <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
      </div>

      <div class="actions">
        <%= f.submit "Sign up" %>
      </div>
      <% end %>

    <%= render "devise/shared/links" %>
</div>
```
登録フォームに名前を登録するフォームが表示できました。
##ストロングパラメータを編集する(devise用)
新規登録時に入力された情報はパラメーターとしてサーバーに送信されます。
ただ、deviseにはコントローラーが存在しないためapplication_controller.rbにdevise