выявление конфликтующих встреч в рельсах работает для обновления, но не для создания? - PullRequest
1 голос
/ 06 августа 2010

Я написал этот метод конфликта, чтобы проверить, сохраняется ли встреча или создала ли уже существующий конфликт с той, которая уже сохранена для конкретного тренера.этот метод вызывается первым делом после того, как человек пытается создать или обновить существующие встречи в 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>

спасибо

Ответы [ 4 ]

3 голосов
/ 06 августа 2010

Вы создаете невозможное условие.Ваше условие говорит, что @new_appointment должно иметь начальное время после appointment конечного времени и конечное время до appointment начального времени ... это логически невозможно.

Я бы предложил использовать это: http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Range/Overlaps.html

Вам нужно будет создать диапазоны на основе времени начала и окончания, выполнив что-то вроде @new_appointment.start_time..@new_appointment.end_time

2 голосов
/ 07 августа 2010

Я думаю, что вы хотели бы сделать это подтолкнуть это к проверке на модели назначения.См. http://api.rubyonrails.org/classes/ActiveRecord/Validations.html#M001391.

В приведенном ниже фрагменте appt_range строит диапазон от времени начала до конца, и метод createate должен вызываться при создании / обновлении.

Возможно, что-то вроде.

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 до 10:30, и он хочет переместить его в 10: 15-> 10:45.Обновление не будет выполнено, так как доктор на данный момент уже забронирован для пациента.Возможно, добавление Patient_id, а не текущий пациент, решит этот крайний случай, но ваши тесты должны охватить эту возможность.

Также я просто выкинул это из головы и не проверял, так что ваш пробег может отличаться (вы не указали версию рельсов ,, а из кода. смотрит на 2.3.x?).Но, надеюсь, это направит вас в лучшую сторону ..

Редактировать ...

Я создал приложение barebones / simple rails 2.3.8, чтобы проверить его, и оно работает надСоздайте.взгляните на http://github.com/doon/appt_test Я также включил базу данных разработчика.

 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

Также в игре с этим, хотя в другом случае вы должны обязательно проверить.Пациент А имеет APT с доктором А от 10-11.Пациент Б имеет аппроксимацию с доктором А с 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

То, что происходит, - это когда часть даты усекается иустановите значение 1 января 2000 г., когда вы извлекаете его из БД. Поэтому, когда вы выполняете запросы к базе данных, диапазоны не будут перекрываться, вы ищете даты в 2010 г. Создание времени начала / окончания для даты и времени решит проблему.вопрос, так как тогда дата будет снова значимой.Еще нужно изменить appt_range, чтобы скорректировать дату обратно на date_of_appointment.Это не происходит при обновлении, так как вы имеете дело со всеми данными из БД.так что все имеют одинаковую дату

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

2 голосов
/ 07 августа 2010

build работает только с объектами, уже сохраненными в базе данных: см. Здесь: http://apidock.com/rails/ActiveRecord/Associations/ClassMethods а тут Ruby on Rails. Как использовать метод Active Record .build в отношении: относится к отношениям?

также, ваш код может использовать рефакторинг. ваш оператор if либо вернет истину, либо ложь, так почему вы не хотите специально возвращать истину? Кроме того, вам не нужны пустые парены, и вы должны определить свои методы, которые возвращают логическое значение, заканчивающееся знаком вопроса. Наконец, почему вы создаете новую встречу в методе 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
0 голосов
/ 06 августа 2010

Количество операторов if else, которые там есть, было больно смотреть.Я не могу сказать, в чем логика.Попробуйте использовать перечисляемый класс для такой работы.Возможно, у вас просто есть ошибка в вашей вложенности.Я обнаружил, что return true часто может иметь нежелательные результаты, например, всегда возвращать true, даже если вы думаете, что логика надежна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...