shibaraku gem をリリースしました
これは何?
ActiveRecord で期間を持つ model を扱う gem です。期間限定公開や、予約公開したいときなんかに使います。
作ったのは 1 年前なんですが、ずっと社内 gem として使用していたものを rubygems.org / github.com に上げました。
USAGE
基本的な使い方
start_at
, end_at
のあるモデルを用意します。
create_table :campaigns do |t|
t.datetime :start_at
t.datetime :end_at
end
shibaraku
と 1 行書くと
class Campaign < ActiveRecord::Base
shibaraku
end
以下の scope やメソッドが生えます。
# 開催中のキャンペーン一覧を取得する
Campaign.in_time
# Campaign Load (0.6ms) SELECT `campaigns`.* FROM `campaigns` WHERE ((start_at IS NULL OR start_at <= '2015-10-19 21:27:58') AND (end_at IS NULL OR '2015-10-19 21:27:58' < end_at))
#=> [#<Campaign id: 1>]
# キャンペーンレコードを
campaign = Campaign.create(start_at: 1.hour.ago, end_at: 1.hour.since)
# 開催中か判定する
campaign.in_time?
# => true
もっと詳しく
チェックするカラム名 start_at
, end_at
は変えられます
過去分詞形でも大丈夫!
create_table :events do |t|
t.datetime :started_at
t.datetime :ended_at
end
class Event < ActiveRecord::Base
shibaraku start_at: :started_at,
end_at: :ended_at
end
Event.in_time
# Event Load (0.3ms) SELECT `events`.* FROM `events` WHERE ((started_at IS NULL OR started_at <= '2015-10-19 22:09:49.411904') AND (ended_at IS NULL OR '2015-10-19 22:09:49.411904' < ended_at))
# => []
テストユーザにだけ公開することができます
「テストユーザのみ test_xxx_at
を見るようにしたい」という要望がありそうなので、第一引数に super_user?
に応答するオブジェクトを渡すことで切り替えられるようにしています。
change_table :campaigns, bulk: true do |t|
t.datetime :test_start_at
t.datetime :test_end_at
end
# 開催中のキャンペーン一覧を取得する
Campaign.in_time(user)
Campaign Load (0.6ms) SELECT `campaigns`.* FROM `campaigns` WHERE ((start_at IS NULL OR start_at <= '2015-10-19 21:27:58') AND (end_at IS NULL OR '2015-10-19 21:27:58' < end_at))
#=> [#<Campaign id: 1>]
# 運営ユーザで開催中のキャンペーン一覧を取得する
Campaign.in_time(super_user)
Campaign Load (0.6ms) SELECT `campaigns`.* FROM `campaigns` WHERE ((test_start_at IS NULL OR test_start_at <= '2015-10-19 21:30:13') AND (test_end_at IS NULL OR '2015-10-19 21:30:13' < test_end_at))
#=> [#<Campaign id: 1>, #<Campaign id: 2>]
読む人にやさしい表示にできます
「10/20 0:00 まで」と表示していた場合、10/20 の 0:00 なのか 24:00 なのか分かりづらいので 「23:59 まで」とすることができます。
campaign.end_at = "2015-10-20 00:00"
I18n.l(campaign.human_readable_end_at)
# => "2015/10/19 23:59:59"
作った経緯
社内のプロダクトのコミットログを見ていたら app/models/concerns/period_module.rb
が追加されていることに気がつきました。
# start_at,end_atのあるActiveRecord用module
module PeriodModule
extend ActiveSupport::Concern
included do
scope :in_time, ->(time = Time.current) do
where("start_at IS NULL OR start_at <= ?", time).where("end_at IS NULL OR end_at >= ?", time)
end
end
def in_time?(current_time: Time.current)
return false if start_at && current_time < start_at
return false if end_at && current_time > end_at
true
end
end
- 「なるほど便利やん 」
- 「
start_at <= now < end_at
と半開区間にしておかないと切り替え時刻ジャストのときにエラーが起きるのでは」 - 「scope で
<=
使ってメソッドで>
を使うの、絶対バグの元になるので記述を合わせたい」 - 「引数なのかキーワード引数なのか。引数名が違うのは何故なのか」
- 「不等号を書くときはなるべく左が小さくなるよう統一しよう」
- 「
in_time?
もうちょいシンプルに書けるだろ」
みたいな諸々のコメントを書きかけたんだけど、どう見ても頻出ロジック。
家に帰ってうちのカミさんに「何か時間に関係する良い名前ない?」と聞いたら 歌舞伎の暫 が出てきたので gem にしました。
なぜ公開してなかったのか
キラキラネームが気になって。。
なぜ公開したのか
「shibaraku って公開しないんですか?」って聞かれたからです。
他の gem と被らない方が重要だし、他の誰かが使いそうな名前でもないしと割り切った。