Feature Toggles

Services & Skills

Share on

Framework-agnostic usage

Features could be defined dynamically:

features = FeatureToggles.build do
  # define env var prefix to enable features
  # globally by passing MY_PREFIX_BAR=1
  env "MY_PREFIX"

  feature :bar do
    user.can_bar?
  end

  feature :foo do |user: nil|
    !user.nil? && user.can_foo?
  end
end

features.enabled?(:bar)
features.enabled?(:bar, user: user)
features.for(user: user).enabled?(:foo)

or loaded from files:

features = FeatureToggles.build(["/path/to/features.rb"])

Rails usage

This is step-by-step guide to add feature_toggles to Rails application.

Step 0. (optional) Add features to User model

class AddFeaturesToUsers < ActiveRecord::Migration
  def change
    # we use a `features` array column to store user's active features
    add_column :users, :features, :string, array: true, default: []
  end
end

Step 1. Define features

Features from file <rails-root-or-engine>/config/features.rb are loaded by convention.

# config/features.rb
env "FEATURE"

feature :chat do |user: nil|
  user&.features.include?("chat")
end

Features will be available at Rails.features after the end of application initialization.

Step 2. Add current_features helper and use it.

class ApplicationController < ActionController::Base
  # ...
  helper_method :current_features

  def current_features
    Rails.features.for(user: current_user)
  end
end

Step 3. Use current_features.

For example, in your navigation template:

<ul>
 <% if current_features.enabled?(:chat) %>
   <li><a href="/chat">Chat</a></li>
 <% end %>
</ul>

Or in your controller:

class ChatController < ApplicationController
  def index
    unless current_features.enabled?(:chat)
      return render template: "comming_soon"
    end
  end
end

Metadata

You can add arbitrary metadata to features:

feature :manual_quantity_backsync, icon: :updated, description: "Manual quantity sync for imported products" do |user: nil|
  !!user&.features&.fetch("manual_quantity_backsync", false)
end

That metadata can be later programmatically accessed and exposed into admin panels, API documentation, etc.

Rails.features.first.metadata
# => { icon: :updated, description: "Manual quantity sync for imported products" }

In the same orbit

Explore more open source projects

Schedule call

Irina Nazarova CEO at Evil Martians

Evil Martians transform growth-stage startups into unicorns, build developer tools, and create open source products. Hire us to design and build your product