🐷

ActiveSupport::Testing::TimeHelpersを使ってRailsの時間を固定した話

2023/02/27に公開

今日は、みてねコールドクターでエンジニアマネージャーをしている遠藤です。

前回までのお話

先日、たけむーが記事を投稿しました。

warekiとtimecopのgemの組み合わせでバグが発生していましたが、ActiveSupport::Testing::TimeHelpersを使用することで回避できました。

今回はその実装方法について説明します。

実装

普段はRSpecなどで使用することの多いActiveSupport::Testing::TimeHelpersですが、アプリケーション内でも使用できるように、以下のように実装しました。

config/initializers/timehelper.rb
if Rails.env.development? || Rails.env.staging?
  require 'active_support/testing/time_helpers'

  include ActiveSupport::Testing::TimeHelpers
end

内部での実装ですが、今回は既存のコードを改修する形で実装したため、concernを使用しました。

app/controllers/concerns/travel_time_concern.rb
module TravelTimeConcern
  extend ActiveSupport::Concern

  included do
    helper_method :current_travel_time
    before_action :enable_travel_time
    after_action :disable_travel_time
  end

  def current_travel_time
    # developでもstagingでもない場合は、current_travel_timeを返さない
    return if !Rails.env.development? && !Rails.env.staging?

    @current_travel_time ||= TravelTime.find_by(is_enable: true)
  end

  def enable_travel_time
    if (Rails.env.development? || Rails.env.staging?) && current_travel_time.present?
      travel_to(current_travel_time.travel_time)
    end
  end

  def disable_travel_time
    return if !Rails.env.development? && !Rails.env.staging?

    travel_back
  end
end

あとは、使用したいcontrollerにincludeするだけです。

app/controllers/xxx_controller.rb
class XxxController < ApplicationController
  include TravelTimeConcern
end

本番に影響することを避けるため、Rails.envを多用してますね…

まとめ

TravelTimeはmodelで、DBに変更するための日付が保存されており、管理画面から変更できるようになっています。

このような実装にしたのは、PMや非エンジニアでも使用しやすくするためです。ただし、安全性やパフォーマンスを考慮する場合は、initializerなどに処理を書いて、環境変数で日時を設定する方がよいかもしれません。

QAや開発しやすくすることが好きなエンジニアを募集中です。

みてねコールドクターテックブログ

Discussion