rails、君に決めた！！~５

一連の記事の目次
[rails、君に決めた！！~目次](https://qiita.com/satousatou/items/d20b61c198a4d439f2e7)

## セッション管理

#### セッションてなんだっけ

`ステートレスなHTTP + セッション、クッキー　＝　ステートフルな通信`
を実現するため、状態を保存する仕組み
ログイン機能とか買い物カゴとかができるようになる

セッション：　サーバー側で管理
Cookie: クライアント（ブラウザ）管理

#### Store(セッションの保存先)の種類

```
CookieStore
CacheStore
ActiveRecoreStore
DalliStore
RedisStore
```

色々あるけど今回はredisで

#### redisセットアップ

```bash
brew install redis

redis-server
```

これでredisサーバが立ち上がった。ターミナルの別ウィンドウで

```bash
redis-cli
```

redisクライアントを起動してredisサーバーにアクセスする。

遊んでみる

```bash
$ redis-cli
127.0.0.1:6379> set foo "honya"
OK
127.0.0.1:6379> get foo
"honya"
127.0.0.1:6379> keys *
1) "foo"
```

`set key value`：値の格納
`get key`: 値の取得

#### railsのセッションストアとしてredisを使う
専用のgemを導入しないといけない

`redis-rails`と`redis-session-store`が有名らしい

今回は、Gemfileに

```
gem 'redis-rails'
```

を追加し、bundle install。

セッションの設定はconfig/initializers/session_store.rbを作り、こんな感じにする

```ruby
Rails.application.config.session_store :redis_store, {
  servers: [
    {
      host: ENV['REDIS_HOST'] || 'localhost',
      port: ENV['REDIS_PORT'] || 6379,
      db: 0,
      namespace: 'session'
    }
  ],
  expire_after: 90.minutes
}
```

ここ本では誤植があったから注意（謎のendが書いてある）

> Redisサーバはローカル環境と本番環境では異なるものを使うため、環境ごとにRedisの接続先を切り替える必要がある

`ENV['REDIS_HOST']`として環境変数を参照する。

```bash
export REDIS_PORT=9999
```

> 環境変数をセットするには、Rails Serverを起動する前にターミナルでexportコマンドを上記のように実行すればいい。

勉強になる。

#### Railsでのセッションの使い方
> コントローラorビューからsessionメソッドとして使う。sessionオブジェクトはハッシュと同じ。

ハッシュがわからずググる。pythonでの辞書みたいなものっぽい。

```ruby
# sessionの読み取り
current_user_id = session[:user_id]

# sessionの書き込み
session[:user_id] = current_user.id

# sessionの一部を削除
session[:user_id] = nil

# session全体を破棄
reset_session
```

## rescue_fromによるエラーハンドリング
ステータスコードのおさらい

| ステータスコード | 意味               |
|------------------|--------------------|
| 1xx              | 処理中             |
| 2xx              | 成功               |
| 3xx              | リダイレクト       |
| 4xx              | クライアントエラー |
| 5xx              | サーバエラー       |

> Railsでは、発生した例外に応じたHTTPステータスコードをある程度自動で返却してくれる。エラーページも静的なものならpublic/xxx.html(public/404.htmlなど)に配置することで返却してくれる。

デフォルトの例外処理以外の処理をさせたい場合にrescue_fromを使う。




- 実際にエラー画面をみたいとき  
config/environments/development.rbに以下の変更を加える。

```ruby
# Show full error reports
config.consider_all_requests_local = false # デフォルトはtrue
```

デフォルトではエラー画面の代わりにデバッグ用のエラー詳細が出力されるから、らしい。まあどうでも良さそう



#### 4xx系のハンドリング
- 例外とHTTPシンボルの対応がみたいとき  
コンソールから`ActionDispatch::ExceptionWrapper.rescue_responses`を呼び出すことで確認できる

```bash
$ bin/rails c
Loading development environment (Rails 5.1.5)
[1] pry(main)> ActionDispatch::ExceptionWrapper.rescue_responses
=> {"ActionController::RoutingError"=>:not_found,
 "AbstractController::ActionNotFound"=>:not_found,
 "ActionController::MethodNotAllowed"=>:method_not_allowed,
 "ActionController::UnknownHttpMethod"=>:method_not_allowed,
 "ActionController::NotImplemented"=>:not_implemented,
 "ActionController::UnknownFormat"=>:not_acceptable,
 "ActionController::InvalidAuthenticityToken"=>:unprocessable_entity,
 "ActionController::InvalidCrossOriginRequest"=>:unprocessable_entity,
 "ActionDispatch::Http::Parameters::ParseError"=>:bad_request,
 "ActionController::BadRequest"=>:bad_request,
 "ActionController::ParameterMissing"=>:bad_request,
 "Rack::QueryParser::ParameterTypeError"=>:bad_request,
 "Rack::QueryParser::InvalidParameterError"=>:bad_request,
 "ActiveRecord::RecordNotFound"=>:not_found,
 "ActiveRecord::StaleObjectError"=>:conflict,
 "ActiveRecord::RecordInvalid"=>:unprocessable_entity,
 "ActiveRecord::RecordNotSaved"=>:unprocessable_entity}
```

- シンボルをステータスコードに変換

`Rack::Utils.status_code`メソッドによってシンボルをステータスコードに変換できる

```bash
[4] pry(main)> Rack::Utils.status_code(:not_found)
=> 404
[5] pry(main)> Rack::Utils.status_code(:conflict)
=> 409
```

例外-シンボル-ステータスコードの対応が見れるのって4系だけなのかな？？
何個か実行してみたけど全部４系で謎い。。。

- デフォルト以外の処理をしたい/動的なエラーページを表示したい  
ApplicationControllerにrescue_fromを宣言する
app/controllers/application_controller.rb

```ruby
class ApplicationController < ActionController::Base
  rescue_from ActiveRecord::RecordNotFound, with: :not_found

  def not_found
    render 'errors/404', status: 404
  end
end
```

> RailsアプリのどこかでActiveRecord::RecordNotFoundが発生した場合、withオプションで指定した関数の処理を実行。public/404.htmlを返すデフォルト処理の代わりに、errors/404という独自のページを返却。

なんとかわかるw

> 独自例外を定義することもできる。独自例外を定義する場合、Exceptionではなく、StandardErrorを継承する。

`独自例外`がまずわからなかった。さっきapplication_controllerに定義したのは、デフォルトで存在する例外に独自の処理を実装する。今回は独自の例外を実装する、ってことか〜、わかりづらい。
違いがわかったところで独自例外ってなんだ。ググる
> Exception
    |
    |- StandardError
    |   |- TypeError とか RuntimeError とかの、アプリケーション側に起因する例外たち
    |   |- 僕らがアプリケーション向けに独自に作成する例外たち
    |
    |- その他の例外: メモリのエラーみたいな、システム側の例外。アプリケーション側では救えない類

あー、なんとなくわかった。HTTPエラーみたいにみんな共通のエラー以外のものってことか。

```ruby
class CustomError < StandardError; end
```

こんな感じで継承するんだって。

#### 5xx系のハンドリング
> 4系に分類されない想定外の例外が発生した時。文法エラー、nilのハンドリングミスなどの実装ミス、ライブラリ(gem)起因のバグ等が含まれる

サーバーエラー。Railsでwebアプリを作った時に、ユーザーの誤操作が4系、アプリ側の問題が５系って理解でいいのかな？

この場合、さっきの独自例外を`rescue_from StandardError`や`rescue_from Exception`を使って定義するのかなーと思いきや、非推奨らしい。

> 5xx系のエラーが内部で発生した場合、処理を続行できる保証がなく、また動的にページを出力する必要性が少ないため

処理が止まっちゃうから独自定義した例外を作っといても実行できないっしょ笑ってことか

じゃあどうするの？
> 5xx系の対応は、public/500.htmlに適切な静的ファイルを事前に配置しておく。想定外の例外が発生した場合、Railsは自動でpublic/500.htmlを返却してくれる。

処理が止まってもRailsが最後の力を振り絞ってpublic/500.htmlを返してくれるんだと。えらい

  
  
今回はセッション管理とエラーハンドリングについて学んだ。実際に運用してみないと実感が掴めないテーマだからふわふわとしか理解できなかったけど、雰囲気は掴めたかな〜。
次回はルータにもうちょっと踏み込むのと、webのセキュリティ対策について書くつもり。