Railsチュートリアル第8章 〜基本的なログイン機構のまとめ(前半)〜

# はじめに
[Railsチュートリアル第8章](https://railstutorial.jp/chapters/basic_login?version=6.0#cha-basic_login)のログイン機構についてのまとめ記事です。
筆者もまだまだ未熟者ですので間違っているところなどはバシバシコメント欄などで指摘してください。
**なお演習の解説や答えなどは載っていません**
**また、いくつかまとめていない節があります(基本的に難しいと感じるところだけを取り上げています)**
# セッション
まずはhttpについて解説します。
httpとは**ステートレス(Stateless)なプロトコル**です。
ステートレスとは文字通り「状態(state)」が「ない(less)」ことです。
HTTPリクエストの1つ1つは前のリクエストの情報を全く利用できないのです。
例えば前のHTTPリクエストがAという情報を持っていたとしても２つ目のHTTPリクエストは情報が利用できないので、その前のHTTPリクエストによって動きを変えることができません。
つまり**ログインしたところでページを移動してしまうとログイン状態が保持されない**のです。
これはHTTPリクエストの特徴であり、ステートレスだからこそシンプルで使いやすく発展したとも言えます。
しかしログイン状態を保持できないのなら使い物になりません。

そこで**セッション(Session)**と呼ばれる半永続的な接続をコンピューター間(パソコンやスマホのwebブラウザとRailsサーバーなど)に別途で設定します。
セッションはHTTPプロトコルとはOSI参照モデルの階層が違うのでHTTPとの特性とは別に(若干影響を受けるものの)接続を確保できます。
![osim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/920666/f368cc39-2f16-7d17-8de3-2c1f94987834.png)
引用：https://bit.ly/3m7muyE (短縮urlです)
HTTPやftp、dnsなどは一番上の**アプリケーション層**ですが、セッションは**セッション層**でお互いに違う階層にいることがわかります。

Railsでセッションを実装する方法として最も一般的なのはcookiesを使う方法です。
<details><summary>Cookieとは</summary>
Cookieとは、Webサイトの提供者が、Webブラウザを通じて訪問者のコンピュータに一時的にデータを書き込んで保存させる仕組み。
CookieにはWebサイト（Webサーバ）側が指定したデータを保存しておくことができ、利用者の識別や属性に関する情報や、最後にサイトを訪れた日時などを記録しておくことが多い。ネットサービスなどのサイトで利用者のIDなどが保存されると、次にアクセスしたときに自動的に利用者の識別が行われ、前回の続きのようにサービスを受けることができる。
1つのCookieには4096バイトのデータを記録でき、1台のサーバが同じコンピュータに対して発行できるCookieの数は20個に制限されている。Cookieの総数は300個までで、これを超えると古い方から削除される。また、個々のCookieには有効期限が設定されており、期限を過ぎたものは破棄される。
参考：https://bit.ly/2PFNWaJ (短縮urlです)
</details>
cookiesはあるページからあるページへ移動したときも廃棄されないので、ここにユーザーIDなどの情報を入れておくことで前回の情報や状態を保ったまま利用できます

## Sessionsコントローラー
ログインとログアウトの要素を、Sessionsコントローラーの特定のRESTアクションにそれぞれ対応させます。
RESRアクションについては[こちら](https://qiita.com/AoiLaurent/items/11fa15093e86ab900626)をご覧ください。

まずはコントローラーの作成ですが`rails generate`で`new`アクションを生成するとそれに対応するビューも生成されます。
`create`や`destory`には対応するビューがないのでnewだけを指定します。
SessionリソースはUserリソースとは違い、専用の`resources`メソッドを使ってRESTfulなルーティングをフルセットで利用する必要がないため、「名前付きルーティング」だけを使います。
名前付きルーティングでは、`GET`リクエストや`POST`リクエストを`login`ルーティングで、`DELETE`リクエストをlogoutルーティングで扱います。

| HTTPリクエスト | URL | 名前付きルート | アクション名 | 用途 |
|:-:|:-:|:-:|:-:|:-:|
| GET | /login | login_path | new | 新しいセッションのページ（ログイン） |
| POST | /login | login_path | create | 新しいセッションの作成（ログイン） |
| DELETE | /logout | logout_path | destory | セッションの削除（ログアウト） |

つまりユーザーがログインしたりするたびにセッションを実行しています。

## ユーザーの検索と認証
ユーザー登録では最初にユーザーを作成しましたが、ログインでセッションを作成する場合に最初に行うのは、入力が無効な場合の処理です。
最初に最小限の`create`アクションをSessionsコントローラで定義し、空の`new`アクションと`destroy`アクションも作成します。

`params`ハッシュでは`session`キーの下にメールアドレスとパスワードがあります。
ユーザー登録の場合と同様でこれらのパラメーターは**ネストしたハッシュ(入れ子になった)**になっています。
ネストしたハッシュとはハッシュの中にハッシュがあることです

```ruby
celebrity = { sports: { soccer: "Osako", basketball: "Htimura" } }
```
`params`の場合次のような入れ子ハッシュになっています。

```ruby
params = { session: { password: "foobar", email: "user@example.com" } }
```
つまり以下のようになります

```ruby
params = { session: { password: "foobar", email: "user@example.com" } }

puts params[:session]
# { password: "foobar", email: "user@example.com" }

puts params[:session][:email]
# "user@example.com"

puts params[:session][:password]
# "foobar"
```
このようになっていてparamsハッシュを使うことでフォームから送信された情報にアクセスできます。

要するに`create`アクションの中では、ユーザーの認証に必要なあらゆる情報を`params`ハッシュから簡単に取り出せるということです。

これでユーザーをデータベースから探して認証できます。

```app/controllers/sessions_controller.rb
class SessionsController < ApplicationController

  def new
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      # ユーザーログイン後にユーザー情報のページにリダイレクトする
    else
      # エラーメッセージを作成する
      render 'new'
    end
  end

  def destroy
  end
end
```

`&&`(論理積(and))は取得したユーザーが有効かどうか決定するために使います。
Rubyでは`nil`と`false`以外のすべてのオブジェクトは真偽値では`true`になるという性質があり、それを考慮して組み合わせを考えると以下の表のようになります

| User | Password | a && b |
|:-:|:-:|:-:|
| 存在しない | **何でも良い** | (nil && [オブジェクト]) == false |
| 有効なユーザー | 誤ったパスワード | (true && false) == false |
| 有効なユーザー | 正しいパスワード | (true && true) == true |

ちなみに論理積(and)はどちらも0のときは0、またはどちらも1のときは1を出力し、それ以外はすべて0を出力します。

| Inpu 1 | Input 2 | Output |
|:------------:|:------------:|:------------:|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |

つまり「ユーザーが存在している(trueなどで1)」「正しいパスワード(trueなので1)」で結果は`true(1)`になります。

# 前半のまとめ

- Railsの``session``メソッドを使うと、あるページから別のページに移動するときの状態を保持できる。一時的な状態の保存にはcookiesも使える
- ログインフォームでは、ユーザーがログインするための新しいセッションが作成できる

# さいごに
最後まで読んでいただきありがとうございました！
この記事が少しでもRailsチュートリアルを進めるのに役に立てたら嬉しいです。
後半は明日の朝に投稿します。
### 参考文献
https://railstutorial.jp/chapters/basic_login?version=6.0#cha-basic_login

https://ansl-blog.hatenablog.com/entry/2019/05/22/OSI%E5%8F%82%E7%85%A7%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A8TCP%EF%BC%8FIP%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

https://e-words.jp/w/Cookie.html#:~:text=Cookie%E3%81%A8%E3%81%AF%E3%80%81Web%E3%82%B5%E3%82%A4%E3%83%88,%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%82%93%E3%81%A7%E4%BF%9D%E5%AD%98%E3%81%95%E3%81%9B%E3%82%8B%E4%BB%95%E7%B5%84%E3%81%BF%E3%80%82

https://xtech.nikkei.com/it/members/ITPro/ITBASIC/20020731/1/