Ruby on rails 在rails中识别冲突约会可以用于更新,但不能用于创建?
我编写此冲突方法是为了检查正在保存或创建的约会是否与已为特定培训师保存的约会冲突。在人员尝试在Ruby on rails 在rails中识别冲突约会可以用于更新,但不能用于创建?,ruby-on-rails,Ruby On Rails,我编写此冲突方法是为了检查正在保存或创建的约会是否与已为特定培训师保存的约会冲突。在人员尝试在def create和def update中创建或更新现有约会后,首先调用此方法 它在更新约会时起作用,但在创建约会时不会识别冲突 有什么想法吗 def is_conflicting() @new_appointment = person.appointments.build(params[:appointment]) @appointments = Appointment.all(
def create
和def update
中创建或更新现有约会后,首先调用此方法
它在更新约会时起作用,但在创建约会时不会识别冲突
有什么想法吗
def is_conflicting()
@new_appointment = person.appointments.build(params[:appointment])
@appointments = Appointment.all(:conditions => { :date_of_appointment => @new_appointment.date_of_appointment, :doctor_id => @new_appointment.doctor_id})
@appointments.each do |appointment|
logger.info( appointment)
if(@new_appointment.start_time < appointment.end_time && appointment.start_time < @new_appointment.end_time)
return true
end
end
return false
end
def create
@appointment = person.appointments.build(params[:appointment])
respond_to do |format|
if(is_conflicting == false)
if @appointment.save
....more code...
end
end
end
end
def update
@appointment = person.appointments.find(params[:id])
respond_to do |format|
if(is_conflicting == false)
if @appointment.update_attributes(params[:appointment])
.....more code...........
end
end
end
end
def冲突()
@new_appointment=person.appointment.build(参数[:appointment])
@预约=预约.全部(:条件=>{:预约日期=>@new\u预约.预约日期,:doctor\u id=>@new\u预约.doctor\u id})
@约会。每个人都有约会|
logger.info(预约)
如果(@new_appointment.start_time
表格中医生设置的部分
<p>
<%= f.label :doctor_id %>
<%= f.select :doctor_id, Doctor.find(:all, :order => "name").collect { |s|
[s.name, s.id]} %>
</p>
“姓名”)。收集{s|
[s.name,s.id]}%>
谢谢你你在创造一个不可能的条件。您的条件是
@新约会
必须在约会
的结束时间之后有一个开始时间,在约会
的开始时间之前有一个结束时间……这在逻辑上是不可能的
我建议使用这个:
您需要根据开始和结束时间创建范围,执行类似于
@new\u appointment.start\u time..@new\u appointment.end\u time的操作。您正在创建一个不可能的条件。您的条件是@新约会
必须在约会
的结束时间之后有一个开始时间,在约会
的开始时间之前有一个结束时间……这在逻辑上是不可能的
我建议使用这个:
您需要根据开始和结束时间创建范围,执行类似于@new\u appointment.start\u time..@new\u appointment.end\u time的操作要查看的if-else语句数。我不知道逻辑是什么。尝试将枚举类用于此类工作。您可能只是在嵌套中出错了。我发现返回true
通常会产生不希望的结果,比如总是返回true,即使您认为逻辑是可靠的
jruby-1.5.0 > apt1 = (1.hour.from_now..2.hour.from_now) #=> Fri, 06 Aug 2010 01:58:43 UTC +00:00..Fri, 06 Aug 2010 02:58:43 UTC +00:00
jruby-1.5.0 > apt2 = (3.hour.from_now..4.hour.from_now)#=> Fri, 06 Aug 2010 03:59:07 UTC +00:00..Fri, 06 Aug 2010 04:59:07 UTC +00:00
jruby-1.5.0 > @appointments = [apt1, apt2]
jruby-1.5.0 > @appointments.any?{|apt| (5.hour.from_now..6.hour.from_now).overlaps? apt } #=> false
jruby-1.5.0 > @appointments.any?{|apt| (1.hour.from_now..3.hour.from_now).overlaps? apt } #=> true
其中if-else语句的数量很难查看。我不知道逻辑是什么。尝试将枚举类用于此类工作。您可能只是在嵌套中出错了。我发现返回true
通常会产生不希望的结果,比如总是返回true,即使您认为逻辑是可靠的
jruby-1.5.0 > apt1 = (1.hour.from_now..2.hour.from_now) #=> Fri, 06 Aug 2010 01:58:43 UTC +00:00..Fri, 06 Aug 2010 02:58:43 UTC +00:00
jruby-1.5.0 > apt2 = (3.hour.from_now..4.hour.from_now)#=> Fri, 06 Aug 2010 03:59:07 UTC +00:00..Fri, 06 Aug 2010 04:59:07 UTC +00:00
jruby-1.5.0 > @appointments = [apt1, apt2]
jruby-1.5.0 > @appointments.any?{|apt| (5.hour.from_now..6.hour.from_now).overlaps? apt } #=> false
jruby-1.5.0 > @appointments.any?{|apt| (1.hour.from_now..3.hour.from_now).overlaps? apt } #=> true
生成仅对数据库中已持久化的对象进行操作:请参见此处:
这里呢
此外,您的代码还可以进行一些重构。您的if语句将返回true或false,那么您为什么要费心专门返回true呢。此外,您不需要空paren,您应该定义返回布尔值并以问号结尾的方法。最后,为什么要在create方法中创建一个新约会,然后在validation方法中创建一个新对象
def conflicting? appointment
@appointments = Appointment.all(:conditions => {... all of them})
# Enumerable#any? returns true or false for the collection,
# so you dont have to specify a return value
# since its the last evaluation in the method
@appointments.any?{|apt| appointment.start_time < apt.end_time && apt.start_time < appointment.end_time} #=> takes each appointment in appointments assigns to apt and checks against the passed in appointment object
end
生成仅对数据库中已持久化的对象进行操作:请参见此处:
这里呢
此外,您的代码还可以进行一些重构。您的if语句将返回true或false,那么您为什么要费心专门返回true呢。此外,您不需要空paren,您应该定义返回布尔值并以问号结尾的方法。最后,为什么要在create方法中创建一个新约会,然后在validation方法中创建一个新对象
def conflicting? appointment
@appointments = Appointment.all(:conditions => {... all of them})
# Enumerable#any? returns true or false for the collection,
# so you dont have to specify a return value
# since its the last evaluation in the method
@appointments.any?{|apt| appointment.start_time < apt.end_time && apt.start_time < appointment.end_time} #=> takes each appointment in appointments assigns to apt and checks against the passed in appointment object
end
我想你要做的是把它推到约会模型的验证上。看
在下面的代码段中,appt_range构建了一个从开始到结束的时间范围,并且应该在创建/更新时调用validate方法
也许是这样
class Appointment < ActiveRecord::Base
def appt_range
start_time..end_time
end
...rest of code...
protected
def validate
@appointments = Appointment.all(:conditions => { :date_of_appointment => date_of_appointment, :doctor_id => doctor_id})
errors.add_to_base("Appointment Conflict") if @appointments.any? {|appt| appt.appt_range.overlaps? appt_range}
end
end
但是,尽管如此(这在您的原始代码中也是一个问题),仍然存在一个竞争条件/问题。假设患者有一个从10:00->10:30的appt,他们想将其移动到10:15->10:45。更新将失败,因为此时已为患者预订了Dr。也许添加患者id(不是当前患者)可以解决边缘问题,但您的测试应该涵盖这种可能性
此外,我只是突然想到了这个问题,还没有对它进行测试,因此您的里程数可能会有所不同(您没有指定rails的版本,而是从code.looks到2.3.x?)。但希望这能为你指明更好的方向
编辑
我构建了一个barebones/simple rails 2.3.8应用程序来测试它,它似乎可以在create上运行。看看我也包括了devdb
rake db:migrate
== CreateAppointments: migrating =============================================
-- create_table(:appointments)
-> 0.0019s
== CreateAppointments: migrated (0.0020s) ====================================
Loading development environment (Rails 2.3.8)
ruby-1.8.7-p299 > a=Appointment.new(:patient_id=>1, :doctor_id=>1, :date_of_appointment=>'08/10/2010', :start_time=>" 2010-08-10 8:00", :end_time=>"2010-08-10 10:00")
=> #<Appointment id: nil, patient_id: 1, doctor_id: 1, date_of_appointment: "2010-08-10", start_time: "2000-01-01 08:00:00", end_time: "2000-01-01 10:00:00", created_at: nil, updated_at: nil>
ruby-1.8.7-p299 > a.save
Appointment Load (0.2ms) SELECT * FROM "appointments" WHERE ("appointments"."doctor_id" = 1 AND "appointments"."date_of_appointment" = '2010-08-10')
Appointment Create (0.5ms) INSERT INTO "appointments" ("end_time", "created_at", "updated_at", "patient_id", "doctor_id", "date_of_appointment", "start_time") VALUES('2000-01-01 10:00:00', '2010-08-07 22:20:33', '2010-08-07 22:20:33', 1, 1, '2010-08-10', '2000-01-01 08:00:00')
=> true
ruby-1.8.7-p299 > b=Appointment.new(:patient_id=>1, :doctor_id=>1, :date_of_appointment=>'08/10/2010', :start_time=>" 2010-08-10 9:00", :end_time=>"2010-08-10 11:00")
=> #<Appointment id: nil, patient_id: 1, doctor_id: 1, date_of_appointment: "2010-08-10", start_time: "2000-01-01 09:00:00", end_time: "2000-01-01 11:00:00", created_at: nil, updated_at: nil>
ruby-1.8.7-p299 > b.save
Appointment Load (0.4ms) SELECT * FROM "appointments" WHERE ("appointments"."doctor_id" = 1 AND "appointments"."date_of_appointment" = '2010-08-10')
=> false
ruby-1.8.7-p299 > b.errors['base']
=> "Appointment Conflict"
ruby-1.8.7-p299 > c=Appointment.new(:patient_id=>1, :doctor_id=>1, :date_of_appointment=>'08/10/2010', :start_time=>" 2010-08-10 11:00", :end_time=>"2010-08-10 12:00")
=> #<Appointment id: nil, patient_id: 1, doctor_id: 1, date_of_appointment: "2010-08-10", start_time: "2000-01-01 11:00:00", end_time: "2000-01-01 12:00:00", created_at: nil, updated_at: nil>
ruby-1.8.7-p299 > c.save
Appointment Load (0.3ms) SELECT * FROM "appointments" WHERE ("appointments"."doctor_id" = 1 AND "appointments"."date_of_appointment" = '2010-08-10')
Appointment Create (0.4ms) INSERT INTO "appointments" ("end_time", "created_at", "updated_at", "patient_id", "doctor_id", "date_of_appointment", "start_time") VALUES('2000-01-01 12:00:00', '2010-08-07 22:21:39', '2010-08-07 22:21:39', 1, 1, '2010-08-10', '2000-01-01 11:00:00')
=> true
现在发生的是,当您从数据库中提取日期部分时,日期部分被截断并设置为2000年1月1日。。因此,当您查询数据库时,范围不会重叠,您正在查找2010年的日期。将开始/结束时间设置为日期时间将解决问题,因为这样日期将再次具有重要意义。否则需要修改应用范围以将日期调整回约会的日期。它不会在更新时发生,因为您正在处理数据库中的所有数据。所以所有的东西都有相同的日期
看
通过强制开始和结束时间使用应用程序的日期来修复它
class Appointment < ActiveRecord::Base
validate :conflicting_appts
def appt_range
start_time..end_time
end
private
def conflicting_appts
@appointments = Appointment.all(:conditions => { :date_of_appointment => date_of_appointment, :doctor_id => doctor_id})
errors.add_to_base("Appointment Conflict") if @appointments.any? {|appt| appt.appt_range.overlaps? appt_range}
end
end
appt.range == Sat Jan 01 09:06:00 UTC 2000..Sat Jan 01 21:10:00 UTC 2000 , my range = Tue Aug 10 09:15:00 UTC 2010..Tue Aug 10 14:19:00 UTC 2010
appt.range == Sat Jan 01 22:06:00 UTC 2000..Sat Jan 01 23:06:00 UTC 2000 , my range = Tue Aug 10 09:15:00 UTC 2010..Tue Aug 10 14:19:00 UTC 2010
appt.range == Sat Jan 01 09:30:00 UTC 2000..Sat Jan 01 12:14:00 UTC 2000 , my range = Tue Aug 10 09:15:00 UTC 2010..Tue Aug 10 14:19:00 UTC 2010
appt.range == Sat Jan 01 09:31:00 UTC 2000..Sat Jan 01 12:20:00 UTC 2000 , my range = Tue Aug 10 09:15:00 UTC 2010..Tue Aug 10 14:19:00 UTC 2010
def appt_range
s=Time.local(date_of_appointment.year, date_of_appointment.month, date_of_appointment.day, start_time.hour, start_time.min, start_time.sec)
e=Time.local(date_of_appointment.year, date_of_appointment.month, date_of_appointment.day, end_time.hour, end_time.min, end_time.sec)
s..e
end