Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何验证Rails中的重叠时间_Ruby On Rails_Ruby_Ruby On Rails 4 - Fatal编程技术网

Ruby on rails 如何验证Rails中的重叠时间

Ruby on rails 如何验证Rails中的重叠时间,ruby-on-rails,ruby,ruby-on-rails-4,Ruby On Rails,Ruby,Ruby On Rails 4,我有一个事件模型,在我的日程表应用程序中有表单时间和到时间,我想在保存之前验证重叠时间 我的观点如下 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 bu

我有一个
事件模型
,在我的日程表应用程序中有
表单
时间和
时间,我想在保存之前验证重叠时间

我的观点如下

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]
时间和
时间可以同时更改和添加

如果我尝试为
Day1
添加(或更改为)
07:05-07:30
,例如,为
Day2
添加(或更改为)
13:50-14:30
等等,我希望显示错误

虽然我尝试了一些代码,其中有
重叠
之间
覆盖
引用or等等,但我无法将它们应用到我的代码中

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"
    ...
  <%= 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>
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
给出以下型号

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

EventsController#Create
EventsController#Update
方法中,检查旧时间之间的新时间,如:

events = Event.where(:departure_date => event_params[:departure_date])
events.each do |event|
 if event_params[:to].between?(event.to, event.from) || event_params[:from].between?(event.to, event.from)
  flash[:error] = "Current Slot Time is already taken!"
  redirect_to :back
  return
 end
end

如果需要服务器端验证,可以在模型类中实现一些
自定义
验证器:

validate :cannot_overlap_another_event
接下来,您需要自己编写此方法:

def cannot_overlap_another_event
  range = Range.new from, to
  overlaps = Appointment.exclude_self(id).in_range(range)
  overlap_error unless overlaps.empty?
end
在解释此代码的作用时,您可以使用
日期创建一个
范围
对象。然后,它使用helper作用域排除
事件本身,并检查此范围内是否有事件

scope :in_range, -> range {
  where('(from BETWEEN ? AND ?)', range.first, range.last)
}
scope :exclude_self, -> id { where.not(id: id) }
overlap\u error
是一种填充模型错误哈希以在屏幕上显示的方法:

def overlap_error
  errors.add(:overlap_error, 'There is already an event scheduled in this hour!')
end
看看这个。关键是定义一个范围来检查重叠的兄弟姐妹。像这样的事情:

# Return a scope for all interval overlapping the given interval, including the given interval itself
  named_scope :overlapping, lambda { |interval| {
    :conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
  }}
def lapse_validation(lapse)
  error = 0
  @active_permits.each do |active_permit|
    unless (lapse[:end] < active_permit[:start] || lapse[:start] > active_permit[:end])
      error = 1
      errors.add(:new_permit, ": The dates you entered overlapp an existing leave period")
    end
  end
  return error
end
#返回与给定间隔重叠的所有间隔的范围,包括给定间隔本身
命名_范围:重叠,lambda{|区间|{
:条件=>[“id”和(DATEDIFF(开始日期),*DATEDIFF(?,结束日期))>=0”,interval.id,interval.end\u日期,interval.start\u日期]
}}

您也可以查看此gem:我认为它会有所帮助。

我在一个项目中遇到了同样的问题,我的解决方案是在模型中包含一个验证方法,因此我有一个休假期间的模型,我必须添加期间(间隔),注意这些间隔不会重叠;假设你有一个失效集合(主动许可证),并且你刚从你的表格中得到一个新的失效(失效),那么只有两个基本规则可以确定这两个期间是否重叠:失效[:结束]必须小于(即发生得更早)主动许可证[:开始]或失效[:开始]必须大于(发生得晚)因此,除非满足其中一个规则,否则这两个时段将重叠。代码必须如下所示:

# Return a scope for all interval overlapping the given interval, including the given interval itself
  named_scope :overlapping, lambda { |interval| {
    :conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
  }}
def lapse_validation(lapse)
  error = 0
  @active_permits.each do |active_permit|
    unless (lapse[:end] < active_permit[:start] || lapse[:start] > active_permit[:end])
      error = 1
      errors.add(:new_permit, ": The dates you entered overlapp an existing leave period")
    end
  end
  return error
end
def失效\u验证(失效)
错误=0
@活动许可证。每个do |活动许可证|
除非(失效[:结束]<有效的许可证[:开始]|失效[:开始]>有效的许可证[:结束])
错误=1
错误。添加(:新建许可证,“:您输入的日期与现有休假期间重叠”)
结束
结束
返回错误
结束

您可以在此处找到关于重叠时段的更详细讨论:

谢谢您的回答,@MurifoX。尽管我编辑了
event.rb
NoMethodError(未定义的方法“from”for 2016-04-06 12:39:00 UTC..2016-04-06 12:40:00 UTC:Range):
app/models/event.rb:17:in“block in”
app/models/event.rb:23:in“不能重叠另一个事件”
app/controllers/schedules\u controller.rb:37:in“创建”
在我尝试创建新计划时显示。我更新了问题底部的
event.rb
。@SamuraiBlue Ops,我的错,你应该使用
范围。第一个
范围。最后一个
,而不是你的模型属性名称。谢谢你的快速回复,@MurifoX。显示另一个错误
SQLite3::SQLException(没有这样的列:start):
。很抱歉在我搜索此错误的含义之前再次询问。@SamuraiBlue这是因为查询使用的是
where('s)(开始
,在您的情况下,
开始
日期是从
命名的。这是因为我在这里复制并粘贴了,哈哈。只要将它从
更改为
,您就可以开始了。@Samurablue可能您的日期格式错误()。另外,在开发过程中使用其他数据库(如
postgres
)也是一种很好的做法。这样,当您使用另一个非SQLITE3的数据库时,在生产中测试时,您就不会感到意外了。这验证了gem是一个救命稻草!这应该是真正公认的答案!谢谢!