我正在学习 RoR。我有一个要求,要求输入用户的日期,但它应该始终是当前日期时间或未来日期。在输入中,用户输入开始日期时间和结束日期时间。目前我使用下面的语法和辅助类来选择日期和时间。
<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 }
这两个验证默认情况下还会检查属性是否存在,因此使用它们可以确保
start_time
和 end_time
都存在,而不是过去,并且 end_time
在或等于 start_time
之后。
这意味着您可以删除
validates :start_time, presence: true
、validates :end_time, presence: true
和您的自定义 validate :valid_start_and_end_time
。
您可以按开始时间然后按标题对事件进行排序,如下所示:
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