So I have a User model, and all I want to be able to do is have a list of available appointment time slots, and have Users select one of them during their registration. I'm envisioning in my head that I would just have some sort of TimeSlotList that would generate TimeSlots in xxx minute increments between two DateTime instances, and then have a User have a TimeSlot as an attribute? Perhaps each TimeSlot would have a taken boolean that indicates whether a User has already taken it?
Is there some sort of standard way to do something like this? I can't imagine that this is too uncommon of a functionality to implement.
Although I'm sure there'll be a gem for this somewhere, I'll see if I can help you with an answer:
Methods
The two methods for handling this are as follows:
time_1 & time_2), creating an Application object directly from the inputTimeSlots (makes "time" irrelevant), and associating the Application object to a TimeSlot
Time.parse
The first way you could do it will be to manually parse the times. I'd do this:
#app/models/appointment.rb
Class Appointment < ActiveRecord::Base
    belongs_to :user
end
#app/models/user.rb
Class User < ActiveRecord::Base
    has_many :appointments
    def valid?  
        taken = where("start <= ? AND end >= ?", start, end)
        save unless taken
    end
end
appointments 
id | user_id | start | end | created_at | updated_at
users
id | etc | etc | created_at | updated_at
#app/controllers/appointments_controller.rb
def new
    @appointment = Appointment.new
end 
def create
    #Validate
    @appointment = Appointment.new(appointment_params).valid?        
end
private
def appointment_params
    params.require(:appointment).permit(:start, :end).merge(user_id: current_user.id)
end
TimeSlots
If you're going to use pre-defined TimeSlots, you could do it like this:
#app/models/time_slot.rb
Class TimeSlot < ActiveRecord::Base
    has_many :appointments
    has_many :users, through: :user_time_slots
end
#app/models/appointment.rb
Class Appointment < ActiveRecord::Base
    belongs_to :time_slot
    belongs_to :user
    def valid?
        taken = where(day: day, time_slot_id: time_slot_id) 
        save unless taken
    end
end
#app/models/user.rb
Class User < ActiveRecord::Base
    has_many :appointments
    has_many :time_slots, through: :appointments
end
time_slots
id | name | time | duration | etc | etc | created_at | updated_at
appointments
id | user_id | time_slot_id | day | created_at | updated_at
users
id | etc | etc | etc | created_at | updated_at
This will allow you to create a system whereby specific TimeSlots will be available to the user. The difference will be that you'll have to validate on the Appointment model, against the TimeSlot & day that's been taken:
#app/controllers/appointments_controller.rb
def new
    @appointment = Appointment.new
end
def create
    #Validate
    valid = Appointment.new(appointment_params).valid?
    #Response
    respond_to do |format|
        if valid
           format.html { redirect_to success_url }
           format.js 
        else
           format.html { redirect_to failure_url }
           format.js
        end
    end
end
private
def appointment_params
    params.require(:appointment).permit(:time_slot_id, :day).merge(user_id: current_user.id)
end
You could optimize this by using some indexes in your DB, to prevent the same day & time_slot being used 
You could have a TimeSlotManager class of sorts that you use to when showing all of the time slots, along with the existing appointments
class Appointment < ActiveRecord::Base
  # :to_time
  # :from_time
  # :on_date
end
class TimeSlotManager
  def initialize(date, appointments)
    @date = date
    @appointments = appointments
  end
  def slots
    # generate slots
    # pass appropriate appointment if time slot within appointment range
  end
end
def TimeSlot
  def initialize(from_time, to_time, appointment=nil)
    @from_time = from_time
    @to_time = to_time
    @appointment = appointment
  end
  attr_accessor :from_time, :to_time, :appointment
end
You at least then would only record the actual appointments.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With