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