【Rails】deviseが最低限使えるようになるためのポイント

## インストール
```rb:Gemfile
gem 'devise'
```
```zsh
$ bundle install
$ rails g devise:install
```
`config/initializers/devise.rb`と`config/locales/devise.en.yml`の2つのファイルが作成され、以下のメッセージが表示される

```:原文
Depending on your application's configuration some manual setup may be required:
  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:
       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
     In production, :host should be set to the actual host of your application.
     * Required for all applications. *
  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:
       root to: "home#index"
     * Not required for API-only Applications *
  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:
       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>
     * Not required for API-only Applications *
  4. You can copy Devise views (for customization) to your app by running:
       rails g devise:views
     * Not required *
```
```:ざっくり翻訳
以下の設定が必要だよ
1. config/environments/development.rbにデフォルトのURLを設定する。
   書き方はこんな感じ↓
   config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
   上記の例は開発環境用だから、本番環境では実際のURLがセットされるようにする
→ 新規会員登録メール、パスワード再設定メールにサイトのURLを埋め込む時とかに使うっぽい。

2. config/route.rbにroot_urlをセットする(普通してる)

3. app/views/layouts/application.html.erbにflashメッセージの表示エリアを作る
   書き方はこんな感じ↓
   <p class="notice"><%= notice %></p>
   <p class="alert"><%= alert %></p>

4. deviseが自動生成するページのデザインをカスタマイズしたい場合、rails g devise:viewsで生成されるフ 
   ァイルを編集する
```

## ユーザーテーブルを作成
```zsh
$ rails g devise User # rails g devise モデル名
```
1. `app/models/user.rb`の生成
2. マイグレーションファイルの作成
3. `config/routes.rb`に`devise_for :users`という記述が追加され、deviseで使うルーティングが作成される

マイグレーションファイルには、デフォルトでメールアドレスやパスワードなど、いろんな項目が設定されている。
必要に応じてカラムを追加。ここではnameというカラムを追加。

```db/migrate/timestamp_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :name # 追加
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at
      t.datetime :remember_created_at
      t.string :name      t.timestamps null: false
    end
    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
  end
end
```
```
$ rails db:migrate
```

## strong parametersを設定
deviseのコントローラーは、ライブラリ側で用意されているので、直接修正できない。
だからdeviseのコントローラーに修正が必要なときは、application_controllerに書く。

今回nameというカラムを追加したので、`configure_permitted_parameters`を上書きしてsignup時にnameを扱えるようにする。

```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters # deviseで使われているstrong_parameterを上書き
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end
```

## before_actionでログインチェック
application_controllerに`before_action :authenticate_user!`をセットして、ログインしないと見れないページにログインせずにアクセスした場合、ログインページにリダイレクトするように設定。

```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  # 省略  
end
```
※ログイン前に見れるページがある場合、そのページのcontrollerに`skip_before_action :authenticate_user!`を設定する。

この時点で
`http://開発環境のIP/users/signup`にアクセスすると、ユーザー登録画面が表示される
`http://開発環境のIP/users/sign_in`にアクセスすると、ログイン画面が表示される
`http://開発環境のIP/users/sign_out`にdeleteでアクセスすると、ログアウトする

これでひとまずユーザー登録、ログイン、ログアウト処理が完成。(※メール認証挟まないからまだ実運用はきつめ)

## 画面を編集する
deviseをインストールした時のメッセージ[4]にもあったようにviewファイルを生成してデザインや項目をカスタマイズする。

```zsh
$ rails g devise:views
```
viewファイルがたくさん生成される。今回はユーザー登録時の画面にname項目を追加。

```erb:app/views/devise/registrations/new.html.erb
<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 %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>
```

## ログインしているかどうかで表示を分ける
```erb
<ul>
<% if user_signed_in? %>
  <li><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></li>
<% else %>
  <li><%= link_to "新規登録", new_user_registration_path %></li>
  <li><%= link_to "ログイン", new_user_session_path %></li>
<% end %>
</ul>
```

## `form_for`を`form_with`に変更
deviseのformはデフォルトで`form_for`を使っているのでより新しい書き方の`form_with`に修正

```erb:app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>
<%= #削除 form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= form_with model: @user, url: user_registration_path, id: 'new_user', class: 'new_user', local: true do |f| %>
```
```erb:app/views/devise/sessions/new.html.erb
<h2>Log in</h2>
<%= #削除 form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= form_with model: @user, url: user_session_path, local: true do |f| %>
```

## ログイン後に遷移する画面を変更
デフォルトだと`root_path`に遷移するようになっているようです。メソッドを上書きして`user_path(user)`に設定してみます。

```app/controllers/application_controller.rb 
class ApplicationController < ActionController::Base
  #省略
  def after_sign_in_path_for(resource)
    user_path(resource)
  end
  #省略
end 
```

## ユーザー詳細ページを作成
これはdevise無視して勝手にcontrollerやviewを作る。編集とか削除とかも同じ、deviseは気にしないで作る。

```zsh
$ rails g controller users show
```
```app/controllers/users_controller.rb
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
  end
end
```
```config/routes.rb
resources :users, only: %i[show]
```
```erb:app/views/users/show.html.erb
<h2>ユーザー詳細</h2>
<p><%= @user.name %></p>
<p><%= @user.email %></p>
```

## remember me機能
デフォルトで使える。
`remember me`にチェックしてログインするとusersテーブルの`remember_created_at`カラムに日付が入る。この日付から一定期間(デフォルトで2週間)は、ブラウザを閉じてもcookieに保存してある情報で自動ログインする。

ログアウトしたり、remember meにチェックを入れずにログインをしたタイミングで`remember_created_at`に`nil`が入る。

[[Rails5]Deviseのログイン判定 | ゆるりエンジニア](https://yuruli.info/rails5-how-to-get-frequency-of-user-login/)

## パスワードリセット機能
デフォルトで使える。
ただメール送信機能ができていない場合メールは送られないので、サーバーのログから、送られるメールの文面(とパスワード再設定用のURL)を確認してアクセスする必要がある。

## ヘルパーいろいろ
```rb
current_user # ログイン中のユーザーのオブジェクト
user_signed_in? # ログインしてるか確認
```

## 参考
- [[Rails5]Deviseのログイン判定 | ゆるりエンジニア](https://yuruli.info/rails5-how-to-get-frequency-of-user-login/)