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