class PreventOverlappingBookings < ActiveRecord::Migration[6.1]
def change
enable_extension 'btree_gist'
execute <<~SQL
ALTER TABLE bookings
ADD CONSTRAINT no_overlapping_bookings
EXCLUDE USING gist (
room_id WITH =,
tstzrange(starts_at, ends_at) WITH &&
);
SQL
end
end
Scheduling/booking is tricky. Postgres exclusion constraints prevent overlapping time ranges at the database layer—far more reliable than application checks. Rails can still validate, but the DB is the source of truth.