我的日程应用程序中有一个Event model时间和start_at时间,我想在保存之前验证重叠时间。
我在cloud9上创建了我的rails应用程序。
我的观点形象如下;

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]

end_at时间和start_at时间可以同时更改和添加。
我想做的是,如果我尝试为end_at添加(或更改为)07:05 - 07:30,例如为Day1添加13:50 - 14:30,则显示错误。
例如;
应用程序开发=从事件中选择*;
 id | start_at |  end_at  | title  | detail | schedule_id |         created_at         |         updated_at
----+----------+----------+--------+--------+-----------------+----------------------------+----------------------------
  1 | 07:00:00 | 07:20:00 | event1 |        |               1 | 2016-04-12 05:28:44.166827 | 2016-04-12 12:52:07.682872
  2 | 10:30:00 | 11:30:00 | event2 |        |               1 | 2016-04-12 05:28:44.17747  | 2016-04-12 12:52:07.689934
  3 | 15:40:00 | 16:10:00 | event3 |        |               1 | 2016-04-12 05:29:07.5005   | 2016-04-12 12:52:07.693477

我在上表中添加了Day2,但验证不起作用。
尽管我问了similar question,但还是建议我使用postgresql而不是sqlite3。
所以我设法配置了postgresql,但结果是一样的。
如果您能告诉我如何检查和显示错误,将不胜感激。
图RB
  create_table "events", force: :cascade do |t|
    t.time     "start_at"
    t.time     "end_at"
    t.string   "title"
    t.integer  "room_id"
    ...

  create_table "rooms", force: :cascade do |t|
    t.string   "room"
    t.integer  "schedule_id"
    ...

  create_table "schedules", force: :cascade do |t|
    t.string   "title"
    t.integer  "user_id"
    t.date     "departure_date"
    ...

给出以下模型:
class Event < ActiveRecord::Base
  belongs_to :room, inverse_of: :events
  has_one :schedule, autosave: false, through: :room
  ...
  validate :cannot_overlap_another_event

  def cannot_overlap_another_event
    range = Range.new start_at, end_at
    overlaps = Event.exclude_self(id).in_range(range)
    overlap_error unless overlaps.empty?
  end

  scope :in_range, -> range {
    where('(start_at BETWEEN ? AND ?)', range.first, range.last)
  }
  scope :exclude_self, -> id { where.not(id: id) }

  def overlap_error
    errors.add(:overlap_error, 'There is already an event scheduled in this hour!')
  end

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
  ...

_ 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 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:'YYYY-MM-DD'});
    });
  </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 :start_at, label: false %>&nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;
              <%= e.input :end_at, 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>

如果您能告诉我如何检查和显示错误,将不胜感激。
编辑
编辑如下:
事件RB
scope :in_range, -> range {
  where('(start_at BETWEEN ? AND ? OR end_at BETWEEN ? AND ?) OR (start_at <= ? AND end_at >= ?)', range.first, range.last, range.first, range.last, range.first, range.last)
}

虽然它看起来很有效,但是当我在不同的日子添加07:05 - 07:30时,这个验证就不起作用了。(参见eventid=8
应用程序开发=从事件中选择*;
id | start_at |  end_at  | title  | detail | room_id |         created_at         |         updated_at
----+----------+----------+--------+--------+-----------------+----------------------------+----------------------------
  1 | 07:00:00 | 07:20:00 | event1 |        |               1 | 2016-04-12 05:28:44.166827 | 2016-04-12 12:52:07.682872
  2 | 10:30:00 | 11:30:00 | event2 |        |               1 | 2016-04-12 05:28:44.17747  | 2016-04-12 12:52:07.689934
  3 | 15:40:00 | 16:10:00 | event3 |        |               1 | 2016-04-12 05:29:07.5005   | 2016-04-12 12:52:07.693477
  8 | 07:05:00 | 07:10:00 | event4 |        |               1 | 2016-04-15 21:37:58.569868 | 2016-04-15 21:39:27.956737

最佳答案

你的检查方向是正确的,但不包括所有的病例。

scope :in_range, -> range {
  where('(start_at BETWEEN ? AND ?)', range.first, range.last)
}

在您的示例中,您最终检查了start_at BETWEEN 7:05 AND 7:30,但第一天的start_at7:00,这超出了该范围。
有四种情况需要处理:
New range overlaps start
Existing:     |------------|
New:      |-------|

New range overlaps end
Existing: |------------|
New:               |-------|

New range inside existing range
Existing: |------------|
New:         |-------|

Existing range inside new range
Existing:    |-------|
New:      |------------|

看,你可以看到前三个案子是通过检查
new_start BETWEEN start_at AND end_at
OR
new_end   BETWEEN start_at AND end_at

那么你只需要通过添加
OR
start_at BETWEEN new_start AND new_end

您可以在end_at上添加类似的代码对称性检查,但这并不是绝对必要的。

关于ruby-on-rails - 如何使用Postgresql验证Rails中的重叠时间,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36575174/

10-16 16:47
查看更多