Skip to Content
Course content

222: Implementing Feature Flags with Flipper

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've been staring at this new PremiumDashboardController for a while now. It's mostly finished, but I'm nervous about pushing it to production. If the new analytics queries I wrote are as slow as they felt in staging, I might bring the whole site to a crawl. My first instinct—the old-school way—was to just wrap the whole thing in a simple conditional.

def index
  if ENV['ENABLE_PREMIUM_DASHBOARD'] == 'true'
    @data = AnalyticsService.fetch_heavy_stats
  else
    redirect_to root_path, notice: "Coming soon!"
  end
end

The "Deploy-to-Change" Headache

This works, sure. But here's the problem: if I notice the database spiking at 2:00 AM, I have to change an environment variable and trigger a full redeploy of the application just to turn the feature off. That's a huge amount of friction for a "kill switch." I want to be able to toggle this feature on the fly without touching the CI/CD pipeline. This is where I usually reach for the flipper gem.

First, I'll add gem 'flipper' to the Gemfile and run bundle. I'm using the ActiveRecord adapter because I don't want to manage a separate Redis instance just for flags. After running the generators to create the necessary tables, I can finally scrap that ENV variable.

def index
  if Flipper.enabled?(:premium_dashboard)
    @data = AnalyticsService.fetch_heavy_stats
  else
    redirect_to root_path, notice: "Coming soon!"
  end
end

Now, I can go into the Flipper console (or use the UI) and flip :premium_dashboard to true. The feature is live. No deploy. No stress. But I've immediately hit a new wall: I don't want everyone to see this yet. I want my internal team and maybe a few "power users" to test it first.

Targeting Specific Users

If I use Flipper.enabled?(:feature_name), it's a global boolean. It's either on for everyone or off for everyone. To make this a true "canary release," I need to pass an "actor" to Flipper. In our case, the actor is the current_user.

Let's try adjusting the check:

def index
  # Passing current_user tells Flipper to check for specific actor permissions
  if Flipper.enabled?(:premium_dashboard, current_user)
    @data = AnalyticsService.fetch_heavy_stats
  else
    redirect_to root_path, notice: "Coming soon!"
  end
end

Now, the logic changes. If the feature is globally "on," everyone gets it. If it's globally "off," Flipper then checks if the current_user specifically has been granted access. I can now go into the console and run Flipper[:premium_dashboard].enable(User.find(1)). User 1 sees the dashboard; everyone else is still redirected. It's a much safer way to roll out risky code.

The Danger of the "Permanent Flag"

Here is something I've messed up in the past: leaving these flags in the code forever. I once found a feature flag in a legacy project from 2017 that was still wrapping a "New Login Page." The "New" page had been the default for five years.

When we use Flipper, we're essentially adding technical debt by design. We are creating multiple code paths. Once the premium_dashboard is fully rolled out to 100% of users and we're sure it's stable, the very next ticket in my sprint isn't a new feature—it's "Remove Flipper flag for Premium Dashboard."

You have to be disciplined. A feature flag is a bridge to a destination; once you've crossed the bridge, you should tear it down so you don't have to maintain it.




📋 Practical Task

Exercise: Implementing a Beta-Only Search Filter

You are working on an e-commerce app. You've built a complex AdvancedSearchFilter that you only want to enable for users with an email ending in @company.com (internal employees) and one specific beta tester with id: 42.

Your Goal:

  • Modify the SearchController#index action to use the flipper gem to guard the AdvancedSearchFilter logic.
  • The feature flag should be named :advanced_search.
  • Ensure the code allows for both global toggling and per-user (actor) enabling.
  • Write a small script or a set of console commands that would:
    1. Keep the feature globally OFF.
    2. Enable the feature specifically for the user with ID 42.
    3. Enable the feature for all users whose email matches the internal company domain.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.