TimeRangeUniqueness
TimeRangeUniqueness is a Ruby gem that provides ActiveRecord migrations and model validation to ensure that time ranges do not overlap within a table. It adds support for creating exclusion constraints on PostgreSQL tstzrange
columns and validates the uniqueness of time ranges in models.
Features
- Migration Additions: Adds a custom method for generating exclusion constraints on time range columns in PostgreSQL using
tstzrange
. - Model Additions: Adds validation to ensure time ranges do not overlap with existing records.
- Supports optional scoping to ensure time ranges are unique within specified contexts (e.g., unique per event name).
Installation
Add this line to your application's Gemfile:
gem 'time_range_uniqueness'
Then execute:
bundle install
Or install it yourself as:
gem install time_range_uniqueness
Usage
Migration Additions
In your migrations, you can use the add_time_range_uniqueness
method to add a time range column with an exclusion constraint. This will prevent overlapping time ranges in your table.
class AddEventTimeRangeUniqueness < ActiveRecord::Migration[6.1]
def change
add_time_range_uniqueness :events,
with: :event_time_range,
scope: :event_name, # Optional scope
name: 'unique_event_time_ranges' # Optional custom constraint name
end
end
Options:
with
: (Required) The name of the column that stores the time range.scope
: (Optional) An array of columns to scope the uniqueness check (e.g.,:event_name
).name
: (Optional) The name of the exclusion constraint. If not provided, a default name is generated.column_type
: The time range column type will always betstzrange
.
Example
class AddEventTimeRangeUniqueness < ActiveRecord::Migration[6.1]
def change
add_time_range_uniqueness :events, with: :event_time_range, scope: :event_name
end
end
This example ensures that the event_time_range
column in the events
table is unique within the scope of the event_name
column.
Model Additions
The gem also provides model-level validation to ensure time ranges do not overlap. You can include this validation in your models like this:
class Event < ApplicationRecord
validates_time_range_uniqueness(
with: :event_time_range,
scope: :event_name,
message: 'cannot overlap with an existing event'
)
end
Options:
with
: (Required) The name of the time range column to validate.scope
: (Optional) An array of columns to scope the uniqueness check (e.g.,:event_name
).message
: (Optional) A custom error message when validation fails (default:'overlaps with an existing record'
).
Example
class Event < ApplicationRecord
validates_time_range_uniqueness with: :event_time_range, scope: :event_name
end
This example ensures that the event_time_range
in the Event
model does not overlap with other events with the same event_name
.
PostgreSQL Requirements
Ensure that your PostgreSQL instance has the btree_gist
extension enabled. The gem will automatically attempt to enable this extension when applying the migration.
CREATE EXTENSION IF NOT EXISTS btree_gist;
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/your_username/time_range_uniqueness.
License
The gem is available as open-source under the terms of the MIT License.