ActiveRecordの日付カラムでレコードを絞り込める by_star gem
移転しました →
久々に便利なの見つけた。有名だったりするのかな?
by_starはモデルの絞り込みに使えるgemで、ActiveRecordとMongoidで使える。
ある期間内のレコードだけを表示したり集計を取ったりというときに使える。自分でも大したコードにはならないんだけど汎用的なものなのでこのgemを使うのが良いでしょう。
githubのREADMEを見れば一目瞭然なのだけど、一応紹介しておく。
Post.by_year(2013) # all posts in 2013 Post.before(Date.today) # all posts for before today Post.yesterday # all posts in 2013 Post.between_times(Time.zone.now - 3.hours, # all posts in last 3 hours Time.zone.now) @post.next # next post after a given post
カラムを指定しない場合はcreated_at
が使われる。自分で定義したカラムを使いたいなら次のようにすればOK。
Post.by_year(2013, field: :hogehoge_at) # hogehoge_at という Date/DateTimeなカラムを使用
こういう絞り込みでよくあるのは○年○月のデータ一覧みたいなのだと思うのでそのやりだけ簡単に書いておく。
Post.by_year # 今年のpost Post.by_month # 今月のpost Post.by_month(4) # 今年の4月 Post.by_month(4, year: 2012) # 2014年の4月
自前カラムを使うならscopeにしとくと便利だと思う。
class Post < ActiveRecord::Base scope :by_year_month, ->(y, m) { by_month(m, year: y, field: :hogehoge_at) } end
実装を見てみると最終的にはbetween_times_query
ていうメソッドに行き着くっぽかった。
def between_times_query(start, finish, options={}) start_field = by_star_start_field(options) end_field = by_star_end_field(options) scope = by_star_scope(options) scope = if options[:strict] || start_field == end_field scope.where("#{start_field} >= ? AND #{end_field} <= ?", start, finish) else scope.where("#{end_field} > ? AND #{start_field} < ?", start, finish) end scope = scope.order(options[:order]) if options[:order] scope end
単機能をいい感じに切り出せてて良さげです。この発想は見習うとこありそう。