ユーザー管理機能

ユーザ管理機能はとても便利なRuby on RailsのGem機能です！
備忘録として投稿します！

### 目的
- deviseを理解
- deviseを使用したユーザー登録の理解
### ログイン機能の実装
- ユーザー登録したユーザーのみがアプリを使えるようにする
- ログインしてないユーザーは投稿機能のアプリだと
新規作成、編集、削除機能などが使えないようにする

### ライブラリのインストール
　#### devise
 ユーザー管理機能を簡単に実装するためのGem
Gemfile
`gem 'devise'`

ターミナル
`bundle install`
Gemインストール後はサーバー再起動
インストールしたGemの反映のタイミングが、サーバー起動時であるため
`ターミナル`

 ### deviseの設定ファイルを作成
 #### rails g devise::innstall コマンド
 追加したdeviseというGemの「設定関連に使用するファイル」を自動で生成するコマンド

 `rails g devise:install`

 ### deviseのUserモデルを作成
 #### rails g deviseコマンド
 deviseによるユーザー機能を対象を指定することで、モデルとマイグレーションの生成やルーティングの設定などをまとめて処理する
 `rails g devise user`

 `config/routes.rb`に自動的にルーティング追加
 `db/migrate/20XXXXXXXXX_devise_create_users.rb`
 メールアドレス
 パスワードのカラム
 レコードの作成日時と更新日時を管理するためのカラム

 #### マイグレーション実行
 `rails db:migrate`
 ローカルサーバー再起動
 
### deviseのビュー作成ーファイル作成
自動的にログイン、サインアップ画面が作成されているがビューファイルとしては生成されていない
deviseのGem内に存在するビューファイルを読み込んでいるため

#### rails g devise:viewsコマンド
deviseに用意されたビューファイルをコピーし、`app/views`の配下に配置してくれるコマンド
`rails g devise:views`

app/views/devise/sessions/new.html.erb
```ruby
<div class="contents row">
  <div class="container">
    <h2>Log in</h2>
    <%= form_with model: @user, url: user_session_path, id: 'new_user', class: 'new_user', local: true 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>
</div>
```

app/views/devise/registrations/new.html.erb
```ruby
<div class="contents row">
  <div class="container">
    <h2>Sign up</h2>
    <%= form_with model: @user, url: user_registration_path, id: 'new_user', class: 'new_user', local: true do |f| %>
      <%= render "devise/shared/error_messages", resource: resource %>

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

      <div class="field">
        <%= f.label :password %>
        <% if @minimum_password_length %>
          <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>
</div>
```
ログイン画面
http://localhost:3000/users/sign_in
サインアップ画面
http://localhost:3000/users/sign_up

### サインアップ時の名前登録

userテーブルにカラム追加
#### rails g nigrationコマンド
マイグレーションを生成するコマンド
`rails g migration Addカラム名To追加先テーブル名　追加するカラム名:型`
テーブルにカラムを追加する際に必要なコードが記述された状態で、マイグレーションが生成

`rails g migration AddNicknameToUsers nickname:string`
`rails fb:migrate`

カラム変更したのでサーバー再起動
`rails s`

### サインアップ画面編集
ニックネームを6文字以内に登録

#### maxlengthオプション
inputタグを生成するヘルパーメソッドである、text_fieldにつけることができるオプション。入力できる最大文字数を指定できる

```ruby
      <div class="field">
        <%= f.label :nickname %> <em>(6 characters maximum)</em><br />
        <% f.text_field :nickname, autofocus: true, maxlength: "6" %>
      </div>
```
### ストロングパラメータ使用する
サインアップ時に入力する情報はパラメーターとしてサーバーに送信される
ストロングパラメーターをコントローラーに記述
しかし、deviseの処理を行うコントローラーはGem内に記述されていうrため、 _*編集することができない*_
また、decviseでログイン機能を実装した場合は、paramsの他に、paramsとは異なる形のパラメーターも受け取る。
deviseのコントローラーにストロングパラメーターを反映する方法と、
devise特有のパラメーターを取得する方法が、必要

#### devise_parameter_sanitizerメソッド
deviseにおけるparamsのようなメソッド。
deviseのUserモデルに関わる「ログイン」「新規登録」などのリクエストからパラメーターを取得
このメソッドとpermitメソッドを組み合わせることにより、deviseに定義されているストロングパラメーターをに対し、自分で新しく追加したカラムを指定して含めることができる。
プライベートメソッドの中に使用。
devidseで定義されているpermitメソッドであり、Railsで初めから使用できたpermitメソッドとは別にする
`devise_parameter_sanitizer.permit( *:deviseの処理名 , keys: [許可するキー])`

####application_controller.rbファイル
全てのコントローラーが継承しているファイル
ここに処理を記述しておくことで、全てのコントローラーで共通となる処理を作ることができる

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

  private
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
  end
end
```
#### before_actionの if
値にメソッド名に指定することで、その戻り値がtrueで会った時にのみ処理を実行するように設定

「deviseにストロングパラメーターを設定するときは特別な記述が必要」

### ログインの有無で表示を変えよう
#### user_signd_in?メソッド
ログインしているかどうかの判定を行う
ユーザーがログインしていればtrue ログアウト状態であればfalseを返す
```ruby
 <% if user_signed_in? %>
          <div class="user_nav grid-6">
          <%= link_to "ログアウト", destroy_user_session_path, data: { turbo_method: :delete } %>
          <%= link_to "投稿する",  new_tweet_path, class: "post" %>
          </div>
        <% else %>
          <div class="grid-6">
            <%= link_to "ログイン", new_user_session_oath, class: "post" %>
            <%= lonk_to "新規登録", new_user_registration_path, class: "post" %>
          </div>
        <% end %>
```
DELETEメソッドを使用する際には「data:{turbo_method::delete}」という指定が必要

### 未ログイン状態のユーザーを転送しよう
#### リダイレクト
「本来受け取ったパスとは別のパスへ転送する」機能
#### unless
`if`と同様に、条件式の返り値で条件分岐して処理を実行するRubyの構文
falseの時にelseまでの処理を実行する
#### redirect_toメソッド
リダイレクト処理を行う際に使用するメソッド
コントローラー等での処理が終わった後、アクションに対応するビューファイルを参照せずに、別ページへリダイレクトさせる
`redirect_to action: :リダイレクト先となるアクション名`
#### exceptオプション
こちらの後に指定したアクションに対しては、事前処理は実行されません

app/controllers/tweets_controller.rb
```ruby
class TweetsController < ApplicationController
  before_action :set_tweet, only: [:edit, :show]
  before_action:move_to_index, except: [:index, :show]
~略~
　private
 ~略~
 def move_to_index
    unless user_signed_in?
      redirect_to action: :index
    end
  end
```
これで、`before_action`により`move_to_index`メソッドが先に実行され、indexアクションのindex.html.erbページにリダイレクトしてくれる

indexアクションにアクセスした場合、indexアクションへのリダイレクトを繰り返してしまい、無限ループが起こる。この対策として、`except: :index`を付け加える
また、ログインしていなくても、詳細ページに遷移できる仕様にするために`exccept:[:index, :show]としている`

unlessで`user_signed_in?`を判定して、その返り値が`false`だった場合にredirect_toが実行される
ユーザーがログインしていない場合には`index`アクションが実行されます。