A Simple feature toggle for a Rails app

… and check why 5600+ Rails engineers read also this

A Simple feature toggle for a Rails app

Photo available thanks to the courtesy of Chris Costes. CC BY 2.0

You’ve probably heard before about feature toggle. Theory looks fine on the paper, but you’re possibly wondering how to implement such feature in your Rails app.

Why even use feature toggles?

It’s neat to use feature toggle when:

  • you want to present some features earlier to the product owner, sales or support teams. It’s much easier to do that on a real system, with real data and not merge multiple branches to staging, seed it with data and then ask everyone to visit it
  • when you work on a big feature and like to commit straight to master. Just disable the new feature on production env so no one can see it and push code to CI
  • you create a dedicated solution for a key customer of the platform you’re working on. Just enable it for given user

Robert recently mentioned interesting use case of feature toggle in his post titled Advantages of working on a legacy application

Somebody already did that

Exactly, there are several gems available which will bring feature toggle to your rails app. I looks like the most popular ones are chili and feature. However, they seemed to be too heavy for our use case and we didn’t want to add another one dependency to our codebase. We wanted to find a dead simple solution.


class FeatureToggle
  def initialize
    @flags = Hash.new

  def with(name, *args, &block)
    block.call if on?(name, *args)

  def on?(name, *args)
    @flags.fetch(name, proc{|*_args| false }).call(*args)

  def for(name, &block)
    @flags[name] = block

Defining toggles

There’s not so much to comment here. The for method is used to define given toggle, eg.

FT = FeatureToggle.new.tap do |ft|
  ft.for(:new_user_profile) do |user_id:|
    Admin.where(user_id: user_id).exists?

And that’s it, now it can be used in the codebase. An instance of FeatureToggle class is assigned to constant FT, so it will be globally available.

Enabling given feature via toggle

Let’s use it for example in controller action to render different, redesigned view instead of the basic one. It will only work for admin users as we stated in toggle definition.

class UserProfilesController < ApplicationController
  def show
    FT.with(:new_user_profile, user_id: current_user.id) do
      return render :new_user_profile, locals: { user: NewUserProfilePresenter.new(current_user) }

    render :show, locals: { user: UserProfilePresenter.new(current_user) }

When given user will meet the criteria (is an admin), a different view will be rendered with new presenter applied.

Final thoughts

This solution is very lightweight and has limited possibilities comparing to gems mentioned at the beginning of the article. However, it helped me a lot with dropping branching. Committing straight to master became a habit. Sales & support team can see features earlier than other users. They are able to review them on a daily basis while normally using the platform. They’re getting more and more familiar with the new behavior, often give valuable feedback. When everything is fine, simple toggle change makes given feature available to all of the users.

You might also like