如何验证 Rails 中的重叠时间 [英] How to validate overlapping times in Rails

查看:41
本文介绍了如何验证 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 等等.

虽然我尝试了一些带有 overlapbetweencover 的代码,参考 这篇文章这篇文章 等等,我无法将它们应用到我的代码中.

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&nbsp;<%= a.index.to_i + 1 %></b></p><%= a.simple_fields_for :events do |e|%><span class="form-inline"><p><%= e.input :from, label: false %>&nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;<%= 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?结尾

解释这段代码的作用,你用你的 fromto 日期创建一个 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&nbsp;<%= a.index.to_i + 1 %></b></p>

        <%= a.simple_fields_for :events do |e| %>
          <span class="form-inline">
            <p>
              <%= e.input :from, label: false %>&nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;
              <%= 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屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆