如何验证 Rails 中的重叠时间 [英] How to validate overlapping times in Rails
问题描述
我有一个 Event 模型
,它在我的日程安排应用中有 form
时间和 to
时间,我想在保存之前验证重叠时间.
我的视图图像如下;
出发日期:2016年12月31日第1天07:00 - 07:20 事件 110:30 - 11:30 活动215:40 - 16:10 活动3[添加事件按钮]第2天08:15 - 09:05 活动 412:08 - 13:04 活动514:00 - 14:25 活动6[添加事件按钮][保存日程按钮]
from
时间和to
时间可以同时更改和添加.
例如,如果我尝试为 Day1
添加(或更改为)07:05 - 07:30
,我想要做的是显示错误, 13:50 - 14:30
用于 Day2
等等.
虽然我尝试了一些带有 overlap
、between
、cover
的代码,参考 这篇文章 或 这篇文章 等等,我无法将它们应用到我的代码中.
schema.rb
create_table "events", force: :cascade do |t|t.time从"t.时间到"t.integer "room_id"...create_table "rooms", force: :cascade do |t|t.integer "schedule_id"...create_table "schedules", force: :cascade do |t|t.integer "user_id"t.date "出发日期"...
给出以下模型:
课程表
_schedule_form.html.erb
<%= render 'shared/error_messages', object: f.object %><%= f.label :title %><%= f.text_field :title, class: 'form-control' %><br><%= f.label :departure_date %><div class="input-group date" id="datetimepicker"><%= f.text_field :departure_date, :value =>(f.object.departure_date.strftime('%b/%d/%Y') if f.object.departure_date), class: 'form-control' %><span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
<script type="text/javascript">$(函数(){$('#datetimepicker').datetimepicker({格式:'MMM-DD-YYYY'});});<br><div id="房间"><%= f.simple_fields_for :rooms do |a|%><div id="room_<%= a.object.object_id %>"><p class="day-number-element-selector"><b>Day <%= a.index.to_i + 1 %></b></p><%= a.simple_fields_for :events do |e|%><span class="form-inline"><p><%= e.input :from, label: false %> - <%= e.input :to, label: false %></p></span><%= e.input :title, label: false %><%结束%>
<%= a.link_to_add "添加事件", :events, data: {target: "#room_#{a.object.object_id}"}, class: "btn btn-primary" %><%= a.input :room %><%结束%>
如果您能告诉我如何检查和显示错误,我们将不胜感激.
编辑!
还是不行
event.rb
class 事件 范围 {where('(\'from\' BETWEEN ? AND ?)', range.first, range.last)}范围 :exclude_self, ->id { where.not(id: id) }def cannot_overlap_another_eventrange = Range.new from, to重叠 = Event.exclude_self(id).in_range(range)除非overlaps.empty?overlap_error?结尾定义重叠错误errors.add(:overlap_error, '这个小时内已经安排了一个事件!')结尾
development.log
<代码>....在 2016-04-07 11:44:59 +0000 开始为 218.33.213.91 发布/schedules"由 SchedulesController#create 处理为 HTML...[1m[35m (0.5ms)[0m 开始事务[1m[36m (0.5ms)[0m [1mSELECT COUNT(*) FROM "events" WHERE ("events"."id" IS NOT NULL) AND (('from' BETWEEN '2016-04-07 07:00:00.000000' 和 '2016-04-07 07:20:00.000000'))[0m[1m[35m (0.3ms)[0m SELECT COUNT(*) FROM "events" WHERE ("events"."id" IS NOT NULL) AND (('from' BETWEEN '2016-04-07 07:05:00.000000' 和 '2016-04-07 07:30:00.000000'))[1m[36mSQL (0.5ms)[0m [1mINSERT INTO "schedules" ("title", "departure_date", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)[0m [["title", "test title"], ["departure_date", "2016-04-10"], ["user_id", 1], ["created_at", "2016-04-07 11:45:00.061460"], ["updated_at", "2016-04-07 11:45:00.061460"]]...
好吧,如果你需要服务器端验证,你可以在你的模型类中实现一些 custom
验证器:
validate :cannot_overlap_another_event
接下来你需要自己编写这个方法:
def cannot_overlap_another_eventrange = Range.new from, to重叠 = Appointment.exclude_self(id).in_range(range)除非overlaps.empty?overlap_error?结尾
解释这段代码的作用,你用你的 from
和 to
日期创建一个 Range
对象.然后它使用辅助作用域排除 Event
本身并检查此范围内是否有事件.
scope :in_range, ->范围 {where('(from BETWEEN ? AND ?)', range.first, range.last)}范围 :exclude_self, ->id { where.not(id: id) }
overlap_error
是一种填充模型的错误哈希以显示在屏幕上的方法:
def overlay_errorerrors.add(:overlap_error, '这个小时内已经安排了一个事件!')结尾
I have an Event model
that has form
time and to
time in my schedule app and I want to validate the overlapping time before saving.
My view image as followings;
Departure date: Dec 31, 2016
Day1
07:00 - 07:20 event1
10:30 - 11:30 event2
15:40 - 16:10 event3
[add event button]
Day2
08:15 - 09:05 event4
12:08 - 13:04 event5
14:00 - 14:25 event6
[add event button]
[save schedule button]
from
time and to
time can be changed and added at the same time.
What I'd like to do is to display error if I try to add (or change to) 07:05 - 07:30
for Day1
, for example, 13:50 - 14:30
for Day2
and so on.
Although I tried some codes with overlap
, between
, cover
with referring to this post or this post and so on, I haven't be able to apply them to my code.
schema.rb
create_table "events", force: :cascade do |t|
t.time "from"
t.time "to"
t.integer "room_id"
...
create_table "rooms", force: :cascade do |t|
t.integer "schedule_id"
...
create_table "schedules", force: :cascade do |t|
t.integer "user_id"
t.date "departure_date"
...
Give the following models:
class Schedule < ActiveRecord::Base
belongs_to :user
has_many :rooms, inverse_of: :schedule
accepts_nested_attributes_for :rooms, allow_destroy: true
...
class Room < ActiveRecord::Base
belongs_to :schedule, inverse_of: :rooms
has_many :events, inverse_of: :room
accepts_nested_attributes_for :events, allow_destroy: true
...
class Event < ActiveRecord::Base
belongs_to :room, inverse_of: :events
has_one :schedule, autosave: false, through: :room
...
_schedule_form.html.erb
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
<br>
<%= f.label :departure_date %>
<div class="input-group date" id="datetimepicker">
<%= f.text_field :departure_date, :value => (f.object.departure_date.strftime('%b/%d/%Y') if f.object.departure_date), class: 'form-control' %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
<script type="text/javascript">
$(function () {
$('#datetimepicker').datetimepicker({format:'MMM-DD-YYYY'});
});
</script>
<br>
<div id="room">
<%= f.simple_fields_for :rooms do |a| %>
<div id="room_<%= a.object.object_id %>">
<p class="day-number-element-selector"><b>Day <%= a.index.to_i + 1 %></b></p>
<%= a.simple_fields_for :events do |e| %>
<span class="form-inline">
<p>
<%= e.input :from, label: false %> -
<%= e.input :to, label: false %>
</p>
</span>
<%= e.input :title, label: false %>
<% end %>
</div>
<%= a.link_to_add "Add event", :events, data: {target: "#room_#{a.object.object_id}"}, class: "btn btn-primary" %>
<%= a.input :room %>
<% end %>
</div>
It would be appreciated if you could give me how to check and display error.
EDIT!
still not work
event.rb
class Event < ActiveRecord::Base
before_save :assign_date
belongs_to :room, inverse_of: :events
has_one :schedule, autosave: false, through: :room
validate :cannot_overlap_another_event
scope :in_range, -> range {
where('(\'from\' BETWEEN ? AND ?)', range.first, range.last)
}
scope :exclude_self, -> id { where.not(id: id) }
def cannot_overlap_another_event
range = Range.new from, to
overlaps = Event.exclude_self(id).in_range(range)
overlap_error unless overlaps.empty?
end
def overlap_error
errors.add(:overlap_error, 'There is already an event scheduled in this hour!')
end
development.log
....
Started POST "/schedules" for 218.33.213.91 at 2016-04-07 11:44:59 +0000
Processing by SchedulesController#create as HTML
...
[1m[35m (0.5ms)[0m begin transaction
[1m[36m (0.5ms)[0m [1mSELECT COUNT(*) FROM "events" WHERE ("events"."id" IS NOT NULL) AND (('from' BETWEEN '2016-04-07 07:00:00.000000' AND '2016-04-07 07:20:00.000000'))[0m
[1m[35m (0.3ms)[0m SELECT COUNT(*) FROM "events" WHERE ("events"."id" IS NOT NULL) AND (('from' BETWEEN '2016-04-07 07:05:00.000000' AND '2016-04-07 07:30:00.000000'))
[1m[36mSQL (0.5ms)[0m [1mINSERT INTO "schedules" ("title", "departure_date", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)[0m [["title", "test title"], ["departure_date", "2016-04-10"], ["user_id", 1], ["created_at", "2016-04-07 11:45:00.061460"], ["updated_at", "2016-04-07 11:45:00.061460"]]
...
Well, if you need a server side validation, you could implement some custom
validators in your model class:
validate :cannot_overlap_another_event
Next you need to code this method yourself:
def cannot_overlap_another_event
range = Range.new from, to
overlaps = Appointment.exclude_self(id).in_range(range)
overlap_error unless overlaps.empty?
end
Explaining what this code do, you create a Range
object with your from
and to
dates. Then it uses the helper scopes to exclude the Event
itself and check to see if there's an event in this range.
scope :in_range, -> range {
where('(from BETWEEN ? AND ?)', range.first, range.last)
}
scope :exclude_self, -> id { where.not(id: id) }
The overlap_error
is a method that populates the model's error hash to display on screen:
def overlap_error
errors.add(:overlap_error, 'There is already an event scheduled in this hour!')
end
这篇关于如何验证 Rails 中的重叠时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!