views:

201

answers:

1

Ok, I have a generic TimeSlot model that deals with a start_at and an end_at for time spans. A couple models derive from this but I'm referring to one in this question: AppointmentBlock which is a collection of Appointments. I want to validate an AppointmentBlock such that no other AppointmentBlocks have been scheduled for a particular Employee in the same time frame. Since AppointmentBlock has a polymorphic association with TimeSlot, you have to access the AppointmentBlock's start_at and end_at through the TimeSlot like so: appt_block.time_slot.start_at This means that I need to have some kind of join in my :conditions for my find() method call. Here is my code so far:

#inside my time_slot.rb model
belongs_to :time_slot_role, :polymorphic => true

 

#inside my appointment_block.rb model
has_one :time_slot, :as => :time_slot_role, :dependent => :destroy
validate :employee_not_double_booked

def employee_not_double_booked
  unless self.employee_id
    # this find's condition is incorrect because I need to join time_slots to get access
    # to start_at and end_at. How can I do this?
    blocks = AppointmentBlock.find(:first,
      :conditions => ['employee_id = ? and (start_at between ? and ? or end_at between ? and ?)',
      self.employee_id, self.time_slot.start_at, self.time_slot.end_at,
      self.time_slot.start_at, self.time_slot.end_at])
    # pseudo code:
    # collect a list of appointment blocks that end after this
    # apointment block starts or start before this appointment
    # block ends that are also associated with this appointment
    # blocks assigned employee
    # if the count is great then 0 the employee has been double
    # booked.

    # if a block was found that means this employee is getting
    # double booked so raise an error
    errors.add "AppointmentBlock",
      "has already been scheduled during this time" if blocks
  end
end

Since AppointmentBlock doesn't have a start_at or an end_at how can I join with the time_slots table to get those conditions to work?

+1  A: 

You can use the :joins parameter on find, similar to this:

 blocks = AppointmentBlock.find(:first,
          :conditions => ['employee_id = ? and (time_slots.start_at between ? and ? or time_slots.end_at between ? and ?)',
            self.employee_id, self.time_slot.start_at, self.time_slot.end_at,
            self.time_slot.start_at, self.time_slot.end_at],
          :joins => 'join time_slots on time_slots.time_slot_role_id = appointment_blocks.id')
William
Thanks William and welcome to StackOverflow! I forgot some important information about my polymorphic relationship (see my edited post). I think to make this work I will need `'join time_slots on time_slots.time_slot_role_id = appointment_blocks.id'`
DJTripleThreat
if you edit your answer using the part i just commented with, I will accept your answer.
DJTripleThreat
Changed the code to reflect your table structure. Glad to be of help.
William