我写了这个冲突方法,以检查保存或创建的约会是否与已为特定培训师保存的约会冲突。在某人尝试在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
医生设置的表格部分。
<p>
<%= f.label :doctor_id %>
<%= f.select :doctor_id, Doctor.find(:all, :order => "name").collect { |s|
[s.name, s.id]} %>
</p>
谢谢
答案 0 :(得分:3)
你正在创造一个不可能的条件。你的条件是@new_appointment
必须在appointment
的end_time之后有一个start_time,在appointment
的start_time之前有一个end_time ......这在逻辑上是不可能的。
我建议使用这个: http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Range/Overlaps.html
您需要根据@new_appointment.start_time..@new_appointment.end_time
答案 1 :(得分:2)
build仅对已经存在于数据库中的对象进行操作:请参阅此处:http://apidock.com/rails/ActiveRecord/Associations/ClassMethods 在这里Ruby on Rails. How do I use the Active Record .build method in a :belongs to relationship?
另外,您的代码仍然可以使用一些重构。你的if语句将返回true或false,所以你为什么要特意返回true。此外,您不需要空的parens,您应该定义返回布尔值的方法,以问号结尾。最后,为什么要在create方法中构建一个新约会,然后在验证方法中创建一个新对象?
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
然后在您的创建或更新方法
中# assuming start/end times are form parameters coming from a view
@appointment = Appointment.new params[:appointment]
# substituting the lookup and update_attributes in the update action, obviously
@appointment.save unless conflicting? @appointment
答案 2 :(得分:2)
我认为您想要做的是将其推迟到约会模型的验证。请参阅http://api.rubyonrails.org/classes/ActiveRecord/Validations.html#M001391。
在下面的代码段中,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
然后您的控制器将
def create
@appointment = person.appointments.new(params[:appointment]))
if @appointment.save
...
end
end
def update
@appointment = person.appointments.find(params[:id])
if @appointment.update_attributes(params[:appointment])
...
end
end
但话虽如此(这也是原始代码中存在的问题),但存在竞争条件/问题。假设患者从10:00开始有一个appt - &gt; 10:30,他们希望将其移至10:15-> 10:45。更新将失败,因为当时已经为患者预约了Dr.也许添加patient_id而非当前患者会解决这种边缘情况,但您的测试应该涵盖这种可能性。
此外,我刚从头脑中扯出来,并没有测试过,所以你的里程可能会有所不同(你没有指定rails的版本,但是从代码中看到。看起来是2.3.x?)。但希望这会让你指向更好的方向..
编辑...
我构建了一个准系统/简单的导轨2.3.8应用程序,以测试它,它似乎适用于创建。看看http://github.com/doon/appt_test我也包括了dev db。
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
这是我的Appointment类(我使用了validate:symbol方法)
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
同样在玩这个,虽然在另一个案例中你应该确定要测试。患者A与10-11的A博士有关。患者B与11-12的博士有关。这些将在当前实施中重叠,因为它们共有11个共同点,并将被标记为冲突。
所以我不确定为什么它不能用于创建,如果你想展示你的代码我们可以看一下。
好的我弄清楚它为什么不起作用,它与开始和结束时间有关。看看这个。
来自测试......(在验证中添加一个记录器向我展示了这一点)。
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
正在发生的事情是日期部分被截断并设置为2000年1月1日,当你从数据库中提取它时..所以当你查询数据库时,范围不会重叠你正在寻找对于2010年的日期。将开始/结束时间设为日期时间将解决问题,因为日期将再次显着。否则需要修改appt_range以将日期调整回date_of_appointment。由于您正在处理来自db的所有数据,因此在更新时不会发生这种情况。所以一切都有相同的日期
请参阅http://github.com/doon/EMR/commit/b453bb3e70b5b6064bb8693cf3986cf2219fbad5
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
通过将开始和结束时间强制转换为使用date_of_appointment ...
来修复它答案 3 :(得分:0)
那里的if else语句的数量很难看。我不知道逻辑是什么。尝试使用可枚举类进行此类工作。您可能只是在嵌套中出错。我发现return 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