はじめに
Rails でアプリ開発をする際、モデルのレコードを where
で絞り込むケースはよくあると思いますが、where
で直接絞れないケースで絞り込む必要があり、その方法について調べました。
課題
例として、Post
モデルを考えます。Post
モデルには、title
と、API からのレスポンス json を保持しておく raw_json
カラムがあります。作成するときはこんなイメージです。
Post.create(
title: 'テスト1',
raw_json: '{"date": "2019-08-01"}'
)
Post.create(
title: 'テスト2',
raw_json: '{"date": "2019-08-02"}'
)
この raw_json
カラムの date
の日付でデータを絞り込む必要があったのですが、この方法について調べていました。
tl;dr
こんなスコープを作りました。
scope :filter_by_tartet_date, -> (target_date) {
return if !target_date.present?
ids = self.select do |s|
if date = JSON.parse(s.raw_json)['date']
Date.parse(date) == Date.parse(target_date)
end
end.map(&:id)
where(id: ids)
}
使い方としては、Post.filter_by_tartet_date('2019-08-01')
という感じで日付文字列を引数に指定すると、raw_json
内の date
が 2019-08-01
のレコードに絞り込んでくれます。
解説
ざっくりしたイメージとしては以下のようになります。
-
select
メソッドで raw_json 内の値を使って比較 -
map
メソッドで対象レコードの id のみの配列を作成 -
where
メソッドで対象 id のレコードのみ絞り込んでActiveRecord::Relation
クラスの戻り値に
select
メソッドを使うだけだと、戻り値が Array
クラスになってしまい、ページネーションなどの使い勝手が悪かったため、最後に where
メソッドで ActiveRecord::Relation
クラスの戻り値に変換して使いやすくしています。
おわりに
直接 where
メソッドで絞れない場合でも、Array
クラスのメソッドを挟んで絞る方法が使えました。直感的に書ける ruby はやっぱり便利だなと感じます。
他にもいい方法ありましたら教えていただけるとありがたいです。