从当前日期时间而不是过去日期时间选择日期和时间范围

问题描述 投票:0回答:1

我正在学习 RoR。我有一个要求,要求输入用户的日期,但它应该始终是当前日期时间或未来日期。在输入中,用户输入开始日期时间和结束日期时间。目前我使用下面的语法和辅助类来选择日期和时间。

<div class="field">
    <%= form.label :start_time %>
    <%= form.datetime_select :start_time %>
  </div>

根据当前表单,这是用户可以从表单中选择的内容:

enter image description here

在这里,我想选择日期和时间范围,使其始终从当前日期时间开始,而不是旧日期时间。

在这里,我想从用户那里捕获未来的事件信息并将其存储到数据库中。

以下是事件模型:

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 中的学习。
如有任何帮助,我们将不胜感激。

ruby-on-rails ruby rubygems
1个回答
0
投票

1.验证

您可以使用

比较验证器
(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 }

这两个验证默认情况下还会检查属性是否存在,因此使用它们可以确保

start_time
end_time
都存在,而不是过去,并且
end_time
在或等于
start_time
之后。

这意味着您可以删除

validates :start_time, presence: true
validates :end_time, presence: true
和您的自定义
validate :valid_start_and_end_time

2.范围

您可以按开始时间然后按标题对事件进行排序,如下所示:

Event.order(start_time: :asc, title: :asc)

翻译为这个 SQL 查询:

SELECT
  events.*
FROM
  events
ORDER BY
  events.start_time ASC,
  events.title ASC

并为您提供按

start_date
(从最旧到最新)排序的事件,然后按
title
(按字母顺序)排序。

在 Rails 中,在 scopes 中使用这些常用查询是很常见的。你可以这样写:

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
© www.soinside.com 2019 - 2024. All rights reserved.