TimePilot

TimePilot is a RubyGem that makes it possible to define features that can be enabled for a certain group of users. It requires very little configuration, and is designed to work stand-alone on any object. TimePilot uses Redis for storage.
Installation
Add this line to your application's Gemfile:
gem 'time_pilot'
And then execute:
$ bundle
Or install it yourself as:
$ gem install time_pilot
Configuration
The features that you want to specify need to be added in an initializer as such:
# config/initializers/time_pilot.rb
TimePilot.configure do |c|
c.feature :planning
c.feature :private_messaging
end
Using this configuration, the TimePilot::Features
module is enriched with three methods per feature at boot time: {feature}_enabled?
, enable_{feature}
and disable_{feature}
. In every model that you would want to invoke these methods, i.e. check if a feature is enabled or either enable or disable it for that group you need to include TimePilot::Features
.
After including TimePilot::Features
add: is_pilot_group
. You can specify an overridden_by: [:foo, :bar, ...]
to specify any relations that override the setting for the object itself. See the example below for Team
and User
.
# app/model/organization.rb
class Organization
attr_accessor :id
include TimePilot::Features
is_pilot_group
end
# app/model/team.rb
class Team
attr_accessor :organization_id, :id
include TimePilot::Features
is_pilot_group overridden_by: :organization
end
# app/model/user.rb
class User
attr_accessor :organization_id, :team_id, :id
include TimePilot::Features
is_pilot_group overridden_by: [:organization, :team]
end
# app/model/person.rb
class Person
attr_accessor :id
include TimePilot::Features
is_pilot_group
end
When you invoke user.planning_enabled?
, TimePilot fill first check if the feature has been enabled for the organization with the ID obtained from user.organization_id
. If that evaluates to false
, TimePilot continues checking the feature, but now using user.team_id
. Then, if that fails too, it checks whether the feature is enabled for the user itself.
Configuring Redis
TimePilot uses localhost:6379
by default for Redis. To connect to a Redis instance on a different port or host, provide a Redis client in TimePilot.configure
block.
# config/initializers/time_pilot.rb
TimePilot.configure do |c|
c.redis Redis.new(...)
end
TimePilot assumes you put in an object that responds to #sadd
, #srem
, #sismember
and #scard
.
Multiple configure blocks
TimePilot allows you to specify more than one configure block. This allows you to specify features at multiple levels. For example, you could specify features in a Rails Engine located in a separate gem, as well as the host application. It's easy as this:
# vendor/gems/.../config/initializers/time_pilot.rb
TimePilot.configure do |c|
c.feature :this_could_be_my_rails_engine
end
# config/initializers/time_pilot.rb
TimePilot.configure do |c|
c.feature :this_is_my_host_application
end
TimePilot Web
TimePilot provides a dashboard that is mountable inside a Rails app.
# in config/initializers/time_pilot.rb
require 'time_pilot/web'
TimePilot::Web.use(Rack::Auth::Basic) do |user, password|
username == ENV["TIME_PILOT_USERNAME"] && password == ENV["TIME_PILOT_PASSWORD"]
end
# in routes.rb
Application.routes.draw do
mount TimePilot::Web => '/time_pilot'
end
TimePilot::Web
is just a Rack app. You can use it outside Rails.
Usage
The configuration above allows you to invoke the following methods on a Organization
, Team
, User
and Person
:
# Methods for feature 'planning'
user.planning_enabled?
user.enable_planning
user.disable_planning
# Methods for feature 'private_messaging'
user.private_messaging_enabled?
user.enable_private_messaging
user.disable_private_messaging
# The same methods can be invoked on an instance of Organization,
# Team and Person provided the example above, since they all include
# the `Features` module.