rails、君に決めた!!~5


一連の記事の目次
rails、君に決めた!!~目次

セッション管理

セッションてなんだっけ

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

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

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

CookieStore
CacheStore
ActiveRecoreStore
DalliStore
RedisStore

色々あるけど今回はredisで

redisセットアップ

brew install redis

redis-server

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

redis-cli

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

遊んでみる

$ 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-railsredis-session-storeが有名らしい

今回は、Gemfileに

gem 'redis-rails'

を追加し、bundle install。

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

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']として環境変数を参照する。

export REDIS_PORT=9999

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

勉強になる。

Railsでのセッションの使い方

コントローラorビューからsessionメソッドとして使う。sessionオブジェクトはハッシュと同じ。

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

# 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に以下の変更を加える。
# Show full error reports
config.consider_all_requests_local = false # デフォルトはtrue

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

4xx系のハンドリング

  • 例外とHTTPシンボルの対応がみたいとき
    コンソールからActionDispatch::ExceptionWrapper.rescue_responsesを呼び出すことで確認できる
$ 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メソッドによってシンボルをステータスコードに変換できる

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

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

  • デフォルト以外の処理をしたい/動的なエラーページを表示したい
    ApplicationControllerにrescue_fromを宣言する app/controllers/application_controller.rb
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エラーみたいにみんな共通のエラー以外のものってことか。

class CustomError < StandardError; end

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

5xx系のハンドリング

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

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

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

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

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

じゃあどうするの?

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

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

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