Rails モデルでの期間フィールドの使用
-
20-08-2019 - |
質問
Rails モデルで期間フィールドを使用する最良の方法を探しています。形式を HH:MM:SS にしたいのですが (例:01:30:23)。使用中のデータベースはローカルでは sqlite で、本番環境では Postgres です。
また、このフィールドを使用して、フィールド内のすべてのオブジェクトを調べて、そのモデル内のすべてのオブジェクトの合計時間を計算して、次のような結果を得ることができるようにしたいと考えています。
合計 45 時間 25 分 34 秒のレコード 30 件。
では、何が最も効果的でしょうか?
- 移行のフィールド タイプ
- CRUD フォームのフォーム フィールド (時、分、秒のドロップダウン?)
- モデル内のすべてのレコードの合計期間を生成する最も安価な方法
解決
- データベースに整数として保存します (おそらく秒数)。
- 入力フォームは正確な使用例によって異なります。ドロップダウンは苦痛です。時間 + 分 + 秒単位の小さなテキスト フィールドを使用することをお勧めします。
- 単に実行してください
SUM
期間列をクエリして総計を算出します。整数を使用する場合、これは簡単かつ高速です。
さらに:
- ヘルパーを使用して、ビューに期間を表示します。期間を秒の整数として簡単に変換できます。
ActiveSupport::Duration
を使用して123.seconds
(交換する123
データベースからの整数を使用します)。使用inspect
結果として得られるものについてDuration
素敵な書式設定のために。(完璧ではありません。自分で何か書いてみてもいいかもしれません。) - モデルでは、おそらく戻り/取得する属性のリーダーとライターが必要になるでしょう。
ActiveSupport::Duration
整数ではなくオブジェクトです。単純に定義するduration=(new_duration)
そしてduration
, 、内部的に呼び出しますread_attribute
/write_attribute
整数引数を使用します。
他のヒント
Railsの5では、ISO8601文字列としてactivesupportの::期間を格納する属性:: ActiveRecordを使用することができます。整数上activesupportの::継続を使用する利点は、箱から出してすぐ、日付/時刻の計算のためにそれらを使用することができるということです。あなたはTime.now + 1.month
と、それは常に正しいだようなことを行うことができます。
ここにありますか。
追加config/initializers/duration_type.rb
class DurationType < ActiveRecord::Type::String
def cast(value)
return value if value.blank? || value.is_a?(ActiveSupport::Duration)
ActiveSupport::Duration.parse(value)
end
def serialize(duration)
duration ? duration.iso8601 : nil
end
end
ActiveRecord::Type.register(:duration, DurationType)
の移行
create_table :somethings do |t|
t.string :duration
end
モデル
class Something < ApplicationRecord
attribute :duration, :duration
end
使用方法
something = Something.new
something.duration = 1.year # 1 year
something.duration = nil
something.duration = "P2M3D" # 2 months, 3 days (ISO8601 string)
Time.now + something.duration # calculation is always correct
私はactivesupportの::期間を使用してみましたが、トラブル出力を明確にするなっていた。
あなたはルビー期間に、正確にある程度の時間を表して不変タイプを好むかもしれませんすぐに。これは、テストやMongoidモデルフィールドの種類がたくさんあります。
私は慢性継続すると一緒に行ったので、また、簡単に人間の期間の文字列を解析したかったです。ここでは秒フィールドにtime_spentを持つモデルにそれを追加する例です。
class Completion < ActiveRecord::Base
belongs_to :task
belongs_to :user
def time_spent_text
ChronicDuration.output time_spent
end
def time_spent_text= text
self.time_spent = ChronicDuration.parse text
logger.debug "time_spent: '#{self.time_spent_text}' for text '#{text}'"
end
end
私はinterval
としてPostgreSQLのActiveRecord::Duration
タイプをサポートして使用するためのいくつかのスタブを書いてきました。
この主旨を参照してください(あなたは、Railsの4.1の初期化子として使用することができます) .COM / Envek / 7077bfc36b17233f60adする
また、私はそこにレールにプルリクエストをオープンしました: https://github.com/rails/rails/pull/16919する