過去の日時ではなく、現在の日時から日付と時刻の範囲を選択します
概要
RoRを勉強中です。ユーザーから日付を入力するという要件が 1 つありますが、常に現在の日付時刻または将来の日付である必要があります。入力では、ユーザーは開始日時と終了日時を入力しています。現在、以下の構文とヘルパークラスを使用して日付と時刻を選択しています。
<div class="field">
<%= form.label :start_time %>
<%= form.datetime_select :start_time %>
</div>
現在のフォームに従って、ユーザーがフォームから選択できるものは次のとおりです。
ここでは、古い日付時刻ではなく、常に現在の日付時刻からになるように日付と時刻の範囲を選択したいと考えました。
ここでは、ユーザーから将来のイベント情報を取得してデータベースに保存したいと考えています。
以下はイベントモデルです。
class Event < ApplicationRecord
validates :start_time, presence: true
validates :end_time, presence: true
validate :valid_start_and_end_time
def start_time
super || end_time
end
private
def valid_start_and_end_time
start_time <= end_time
end
end
およびイベントコントローラー:
class EventsController < ApplicationController
before_action :set_event only: [:show, :edit, :update, :destroy]
def index
@event = Event.all.where('start_time > ?', Time.now).sort_by(&:start_time).sort_by(&:title)
end
def create
@event = Event.new(event_params)
@event.save
end
private
def event_params
params.require(:event).permit(:title, :start_time, :end_time)
end
end
基本的に、ここでやりたいことは次のとおりです。 1. ユーザーに開始日時と終了日時を入力してもらいます。すべて将来のイベントにするか、少なくとも検証を追加する必要があります。 2. モデルでは、イベント インデックスを start_time で並べ替え、次にタイトルで並べ替えたいと考えています。
RoR での学習を強化できるように、最適なアプローチでどのように実行できるかを理解するのを誰かが助けてくれませんか。 ここで何か助けていただければ幸いです。
解決策
比較バリデータ (Rails 7 で追加) を使用して、start_time が過去であってはいけないことを検証できます。
validates :start_time, comparison: { greater_than_or_equal_to: Time.current }
比較バリデーターを使用して、end_time が start_time 以降でなければならないことを検証することもできます。
validates :end_time, comparison: { greater_than_or_equal_to: :start_time }
この 2 つの検証では、デフォルトで属性の存在もチェックされるため、start_time と end_time が過去ではなく両方とも存在すること、および end_time が start_time 以降であることを確認できます。
つまり、 validates :start_time、presence: true、validates :end_time、presence: true、およびカスタム validate :valid_start_and_end_time を削除できることを意味します。
次のように、start_time でイベントを並べ替え、次にタイトルでイベントを並べ替えることができます。
Event.order(start_time: :asc, title: :asc)
これは次の SQL クエリに変換されます。
SELECT
events.*
FROM
events
ORDER BY
events.start_time ASC,
events.title ASC
イベントが start_date (古いものから新しいもの) 順に並べられ、次にタイトル (アルファベット順) 順に表示されます。
Rails では、これらの一般的に使用されるクエリをスコープ内に置くのが非常に一般的です。これを次のように書きます。
scope :sorted, -> { order(start_time: :asc, title: :asc) }
このスコープを定義すると、Event.order(start_time: :asc, title: :asc) の代わりに Event.sorted を使用できます。
イベント コントローラーで where(‘start_time > ?’, Time.now) を使用しているため、そのスコープも必要だと思います。次のように定義できます。
scope :upcoming, -> { where('start_time > ?', Time.current) }
インデックス アクションは次のように書き換えることができます。
def index
@events = Event.upcoming.sorted
end
これにより、次の SQL クエリが作成されます。
SELECT
events.*
FROM
events
WHERE
(start_time > '2024-05-10 21:03:50.413480') -- the current time
ORDER BY
events.start_time ASC,
events.title ASC