目次
redis-objectsについて
redis-objectsとはRedisのデータ型をRubyのオブジェクトにマッピングすることでRedisにRuby的なインタフェースを提供するgemです。
Redis::Objectsの利用用途は以下の2つです。
- モデルとRedis::Objectsを紐付け、モデルに関連するデータをRedisに保存する
- モデルとは紐付けず、Redis::Objects単体で利用する
今回はそれぞれの利用方法について紹介します。利用するredis-objectsのバージョンは1.5.1
です。
下準備
RailsアプリケーションでRedis::Objectsを利用するための下準備について紹介します。
Redisのインストール
RailsアプリケーションでRedisを利用できるようにするため、まずはRedis本体をインストールします。
ローカルの場合
### redisのインストール
$ brew install redis
### redisサーバの起動
$ redis-server
Dockerの場合
Redis用のコンテナをdocker-compose.yml
に追加すればOKです。
version: '3'
services:
app: # アプリケーションコンテナ
(略)
depends_on:
- redis # redisコンテナを依存関係に追加
redis: # Redisコンテナ
image: redis:latest
volumes:
- redis-data:/data # Redisデータの永続化
volumes:
redis-data:
Gemの追加
Gemfile
gem 'redis-objects'
Redisのイニシャライザを作成する
Redis::ObjectsがRedisに接続できるようにするためRedisの接続情報を設定します。
Redis::ObjectsはRedis::Objects.redis
が設定されていない場合Redis.current
をデフォルトで利用できます。1
Railsアプリケーションの場合Redis.current
はconfig/initializers/redis.rb
で定義します。
config/initializers/redis.rb
# Docker環境のRedisを利用する場合、host名はRedisのコンテナ名にする
Redis.current = Redis.new(host: '127.0.0.1', port: 6379, db: 0)
利用用途1: モデルとRedis::Objectsを紐付け、モデルに関連するデータをRedisに保存する
UserモデルでRedis::Objectsを使用する例をもとに、モデルとRedis::Objectsを紐付けるケースの利用方法について紹介します。
モデルの修正
モデルにRedis::Objectsをインクルードします。
user.rb
class User < ApplicationRecord
+ include Redis::Objects
counter :my_posts
end
Redis::ObjectsはRedisの各APIに対応したオブジェクトを用意しています。
ですので、以下の方法で利用するRedisオブジェクトのタイプとフィールド名を宣言します。
[Redisオブジェクトのタイプ] [フィールド名]
Redisオブジェクトのタイプの詳細についてはredis-objectsのREADMEをご参照ください。
たとえばmy_posts
という名前のRedis::Counter
をモデルに紐付ける場合は以下のようになります。なお、Redis::Counter
はカウントに関するオブジェクトです。
user.rb
class User < ApplicationRecord
include Redis::Objects
+ counter :my_posts
end
Redis::Objectsで生成されるデフォルトのキー名は"#{モデル名}:#{self.id}:#{フィールド名}"
です。
ですので、上記の例であればuser:[インスタンスのid]:my_posts
というキーでRedisにデータが保存されます。
動作確認
モデルとRedis::Objectsを紐づけたので、実際にデータが保存されているか確認します。
$ rails c
### モデルに紐づくRedis情報の確認。イニシャライザの設定が利用されている
> User.redis
=> #<Redis client v4.3.1 for redis://redis:6379/0>
### インスタンスの作成
> user = User.create(name: "Bob", active: true)
### フィールド名を参照するとRedisオブジェクトのタイプがわかる
> user.my_posts
=> #<Redis::Counter:0x000055f89ff358c0>
### Redis::Counterのincrementメソッドを実行
> user.my_posts.increment # or incr
=> 1
### Redis::Counterのdecrementメソッドを実行
> user.my_posts.decrement # or decr
=> 0
### Redis::Counterのincrement(num)メソッドを実行
> user.my_posts.increment(3)
=> 3
### valueメソッドで値を確認できる
> user.my_posts.value
=> 3
### モデルに紐づくRedisで利用しているキーの一覧
> User.redis.keys('user:*')
=> ["user:1:my_posts"]
redis-cli
でRedisの中身を確認するとRedis::Counter
のデータが反映されていることがわかります。
$ redis-cli
### DBの選択
> select 0
OK
### 保存されているキーの数
> dbsize
(integer) 1
### キーの一覧
> keys *
1) "user:1:my_posts"
### valueの種類の確認
> type user:1:my_posts
string
### valueの取得(Stringはgetで取得)
> get user:1:my_posts
"3"
補足事項について
モデルとRedis::Objectsを紐付ける際の補足事項について紹介します。
Redis::Objectsを利用するモデルにidがない場合はidメソッドを作成する
Redis::Objectsはユニークな値を返すidメソッドを提供するクラスで動作します。
ですので、idのない独自クラスでRedis::Objectsを利用する場合はidメソッドを実装する必要があります。
たとえば独自クラスfoo.rb
でRedis::Objectsを利用する場合は以下のようになります。
lib/foo.rb
class Foo
include Redis::Objects
value :data
def initialize(id)
@id = id
end
# idメソッドは『attr_reader :id』でもOK
def id
@id
end
end
モデルとRedis::Objectsを紐づけたので、実際にデータが保存されているか確認します。
$ rails c
> require 'foo'
> foo = Foo.new(1)
> foo.data
=> #<Redis::Value nil>
> foo.data = "example data"
> foo.data.value
=> "example data"
redis-cli
でRedisの中身を確認すると、Fooモデルのデータが反映されていることがわかります。
$ redis-cli
### DBの選択
> select 0
OK
### 保存されているキーの数
> dbsize
(integer) 1
### キーの一覧
> keys *
1) "foo:1:data"
### valueの種類の確認
> type foo:1:data
string
### valueの取得(Stringはgetで取得)
> get foo:1:data
"example data"
キーを変更したい場合
キー名はkey:
で任意の文字列に変更できます。具体例は以下の通りです。
user.rb
class User < ApplicationRecord
include Redis::Objects
counter :my_posts, key: ->(instance) { "it:is:new:key:#{instance.id}:good" }
end
なお、idを含めない形のキー名にした場合でもidメソッドの定義は必須です。もしidメソッドがないクラスでRedis::Objectsを利用しようとするとエラーが発生します。
以下はidメソッドがないクラスでRedis::Objectsを利用してエラーになる例です。
lib/foo.rb
class Foo
include Redis::Objects
value :data, key: ->(instance) { "foo:#{instance.code}:data" }
def initialize(code)
@code = code
end
attr_reader :code
end
$ rails c
> require 'foo'
> foo = Foo.new("abc")
> foo.data = "example data"
Traceback (most recent call last):
2: from (irb):30
1: from (irb):31:in `rescue in irb_binding'
NoMethodError (undefined method `id' for #<Foo:0x0000557dbeba3c90 @code="abc">)
Redisの接続情報を変更したい場合
[モデル名].redis = Redis.new
で再定義をすると接続先のRedisを変更できます。
具体的には以下の通りです。
$ rails c
### イニシャライザで定義されたRedis.currentが利用される
> User.redis
=> #<Redis client v4.3.1 for redis://redis:6379/0>
### dbを0から10に変更する
> User.redis = Redis.new(host: 'redis', port: 6379, db: 10)
### 『redis://redis:6379/10』から分かるように、DBが10に変更されている
> User.redis
=> #<Redis client v4.3.1 for redis://redis:6379/10>
### DB番号10にデータを作成してみる
> user = User.create(name: "Bob", active: true)
> user.my_posts.increment # or incr
=> 1
redis-cli
でRedisの中身を確認すると、Redis::Counter
のデータが反映されていることがわかります。
$ redis-cli
### DBの選択
> select 10
OK
### 保存されているキーの数
> dbsize
(integer) 1
### キーの一覧
> keys *
1) "user:1:my_posts"
利用用途2: モデルとは紐付けず、Redis::Objects単体で利用する
redis-objectsのREADMEでスタンドアローンと呼ばれている方式です。
Redisの操作をRedis APIを直接記述するのではなくRubyオブジェクトっぽく記述したい場合にスタンドアローン方式を利用します。
スタンドアローン方式の利用手順は以下の通りです。
- 『Redis::[クラス名].new(key名)』でRedisインスタンスを作成する
- インスタンスメソッドを利用してインスタンスに保存されているデータを更新する
Redis::ObjectsはRedisの各APIに対応したオブジェクトを用意しています。今回は例としてRedis::Counter
の利用方法について紹介します。
### Redisインスタンスの作成
@counter = Redis::Counter.new('counter_name')
### Redis::Counterのインスタンスメソッドを利用してデータ更新
@counter.increment # or incr
=> 1
@counter.decrement # or decr
=> 0
@counter.increment(3)
=> 3
### valueメソッドで保存されているデータを確認
@counter.value
=> 3
redis-cli
でRedisの中身を確認すると、スタンドアローン方式で生成したRedisのデータが反映されていることがわかります。
$ redis-cli
### DBの選択
> select 0
OK
### 保存されているキーの数
> dbsize
(integer) 1
### キーの一覧
> keys *
1) "counter_name"
### valueの種類の確認
> type counter_name
string
### valueの取得(Stringはgetで取得)
> get counter_name
"3"
まとめ
- Redis::Objectsにはモデルと紐付ける方法とスタンドアローンの2種類の使い方がある
- Railsの場合、Redis::ObjectsのRedisの設定はイニシャライザで定義する
- モデルで利用する場合はRedis::Objectsのincludeと、Redisオブジェクトのタイプを定義する
- Redis::Objectsを利用するモデルはidメソッドが必須
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!