gem Redisを導入して、セッション情報を管理した話

## 何をしたか
とあるRailsのカリキュラムを実施しています。セッション情報の管理に[Redis](https://github.com/redis-store/redis-rails)を使うことになっていましたが、初めてつかうgemなので、簡単に内容を調べてみました。

なお、実行環境は以下の通りです。

- `Rails 5.2.3`

## 2020年12月時点にあった、公式からのお知らせ
まずは、[公式のドキュメント](https://github.com/redis-store/redis-rails)で内容を把握しようとしたところ、初めにこんなことが書いてありました。

> Rails 5.2.0にはすぐに使えるRedisキャッシュストアが含まれているため、フラグメントキャッシュをRedisに保存するだけでよい場合は、このgemはもう必要ありません。 redis-activesupport gemのメンテナンスは、セキュリティと互換性の問題のために継続されますが、新しい機能は受け付けていません。セッション管理用のredis-actionpackやHTTPキャッシュストレージ用のredis-rack-cacheなど、redis-storeファミリーの他のすべてのgemを引き続き積極的に維持しています。

こ、、、これは、、、、。`Rails5.2.0`以上ではこのgemは必要ないということなのでしょうか？？
とりあえず上記文章中にあった、[フラグメントキャッシュ](https://railsguides.jp/caching_with_rails.html#%E3%83%95%E3%83%A9%E3%82%B0%E3%83%A1%E3%83%B3%E3%83%88%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5)という単語は何かわからなかったので、調べてみました。

それによると、フラグメントキャッシュは、ビューの情報の再読み込みに関するキャッシュなのですね。

つまり、上記の記述はビューの情報をキャッシュするだけならこのgemは不要とのことなので、今回のセッション情報管理には引き続き使って良さそうです。よかった。

でも、同じく[公式のドキュメントのセッション情報管理の部分](https://github.com/redis-store/redis-rails#session-storage)には、「今後は直接[redis-actionpack](https://github.com/redis-store/redis-actionpack)を利用してね」とあるので、今後は、こちらを利用するのが良いのかもしれないですね＾＾

## Gemの概要

公式の情報では、なかなか「どんなgemなのか」が把握しづらかったので、こちらの記事を参考にさせていただきました。

[Redisとは？RailsにRedisを導入](https://qiita.com/hirotakasasaki/items/9819a4e6e1f33f99213c)

それによると、Redisには以下の特徴があるようです。

> キャッシュシステムとして有名であり、NoSQLの1つ
・NoSQLの中でも、KVS(キーバリューストア)。キーとバリューの組み合わせを保存する。
・データ型にいろいろ使える
・String,List,Set,Sorted Set,Hash
・インメモリなので高速
・永続化設定可能
・シングルスレッド
・スケールアウト可能
・使いどころ
　　・セッションなど有効期限のあるデータを扱う場合
　　・ランキングデータなど重たいSQLを走らせないといけない処理を扱う場合

...わからない単語も多かったので、以下、調べたことを追記します。

- `NoSQL`...[SQLを使わずにデータの操作ができるデータベース言語のこと](https://academy.gmocloud.com/qa/20160509/2284)だそうです。jsonなどがこれにあたります。
- `インメモリ`...[データをディスクや SSD に保存するデータベースではなく、データストレージ用のメモリに主に依存](https://aws.amazon.com/jp/nosql/in-memory/)するもの、だそうです。
- `シングルスレッド`...[処理の開始から終了まで線を引いたときに1本の線で書ける、枝分かれしない処理](https://wa3.i-3-i.info/diff165thread.html)のことだそうです。

...なるほど。ようやく概要がわかってきました。

## 導入手順
それでは、導入していきます。まずは、以下を`Gemfile`に記載して、`bundle install`します。

```Ruby:Gemfile
gem 'redis-rails'
```

次に、`config/initializers/session_store.rb`（なければ新規作成）に、以下を記入します。なお、この部分は[公式の記述](https://github.com/redis-store/redis-rails#session-storage)のままだと、CSRF関係でエラーが出たので、私は、[こちらのブログ記事](https://ccbaxy.xyz/blog/2020/06/21/ruby47/#sono-2-redis-rails-woyong-itesetusiyonsutorezisutoadeshe-ding)を参考に、以下のように記載しました。

```Ruby:config/initializers/session_store.rb
MyApp::Application.config.session_store :redis_store, expire_after: 1.day, servers: {
  host: "localhost",
  port: 6379,
  namespace: "user_sessions",
  signed: true,
  secure: true
}
```
それぞれのオプションの説明も公式に書いてありましたので、以下、Google翻訳の力を借りて、メモしていきます。

- `servers`...データの検索を試みるRedisサーバーのURLの配列(6379はRedisのデフォルト値)
- `expire_after`...セッションキーのデフォルトのTTL([寿命](https://wa3.i-3-i.info/word13138.html))。これは、セッションストアによって生成されたCookieの有効期限としても設定されます。
- `key`...クライアント側のCookieの名前です
- `threadsafe`...複数のインスタンスで実行されるアプリケーション用です。セッションデータのグローバルミューテックスロック（[二人以上が同時に使えなくする仕組み](https://wa3.i-3-i.info/word13360.html)）を無効にする場合は、これをfalseに設定します。これはデフォルトでtrueであり、ミューテックスが有効になることを意味します。
- `signed`...署名済み/暗号化されたCookieを使用してローカルセッションをクライアントマシンに保存し、悪意のあるユーザーがそのコンテンツを改ざんするのを防ぐ
- `secure`...HTTP Cookieがセキュア（HTTPS）接続でサーバーからクライアントに転送されることを保証

なるほど、オプションについてもかなり理解ができました。
では、早速使用していきます。

## 使い方
Redisは**セッション情報をRedisサーバーに入れる**という形で、セッション情報が開発者に見えるようにしてくれています。そのため、まずは（Railsアプリケーション起動前に）Redisサーバーを起動する必要があります。

```
$ redis-server
```

Redis導入後はRedisサーバーを立ち上げずにRailsサーバーを立ち上げるとエラーになりますので、ご注意ください。

その後、別ウィンドウで`redis-cli`を実行します。

```
$ redis cli
127.0.0.1:6379> # コマンドを入力できます
```
以降、さまざまなコマンドを入力することで、Redisサーバーの情報を読み書きできます。

### コマンド操作
Redis全てのコマンド情報は[こちら](https://redis.io/commands)から見ることができますが、ここでは、セッション情報を見るのに十分な内容だけを紹介します。

なお、[こちらのブログ記事](https://blog.eiel.info/blog/2014/08/26/remember-redis/)も大変参考にさせていただきました。

**`KEYS *`**で登録されている全てのキーを見ることができます。

```
> KEYS *
1) "user_sessions:2::f7ab4de876c20536e1e391a21bac...."
```

先ほど、Redisの設定で`namespace: "user_sessions"`を指定していたため、セッション情報にはプレフィックス的に`user_sessions`がついています。
`KEYS`にはワイルドカードが使えるため、

**`KEYS user_sessions*`**と入力すると、

```
> keys user_sessions*
1) "user_sessions:2::f7ab4de876c20536e1e391a21bac...."
```
ユーザーセッションに関するキーだけがみられます。（表示上は先ほどと変わりませんが^^;)

Redisではデータ型によってValue値の取得方法が違うようです。なので、まずは先ほど得た`KEY`のデータ型を確認します。

**`TYPE キー名`**でデータ型を確認できます。

```
> type 1) "user_sessions:2::f7ab4de876c20536e1e391a21bac...."
string
```

string型のkeyのvalueを取得するのは`GET`なので、

**`GET キー名`**と入力すると、sessionのvalue値が確認できました。

```
get 1) "user_sessions:2::f7ab4de876c20536e1e391a21bac...."
"\x04\b{\aI\"\x10_csrf_token\x06:\x06EFI\...."
```

セッション情報って、こんな形をしているのですね。。。

## 感想
実装は以上となります。初めて使うgem、しかもアウトプットをするまでが課題、とのことでかなり慎重に調べてみましたが、おかげで公式ドキュメントの読み方がかなりわかってきました。
また、しっかりドキュメントを読んでから実装に入るとgemがどういう仕組みで動いているのか、しっかり頭に入るので、エラー解決も早くなりそうです。

引き続き、頑張っていきます。

### 追記：dump.rdbというファイルが生成されてしまう件について
自分の場合はRedisの導入によって`dump.rdb`というファイルがカレントディレクトリに生成されてしまったのですが、以下の方法で回避できました。

[dump.rdbがカレントディレクトリに生成されてしまう](https://blog.kotamiyake.me/tech/output-dump-rdb-to-current-directory/)