Rails Feature Flags: Now So Flippin' Easy You Won't Believe It
6 min read

Rails Feature Flags: Now So Flippin' Easy You Won't Believe It

Well friends today is a great day. I'm writing to let you know that Flipper 0.21 is hot off the press. And. It. Is. Awesome. Seriously, read on.
Rails Feature Flags: Now So Flippin' Easy You Won't Believe It

As I said in the title, getting started with feature flags in your Rails apps has never been easier. With the latest release of Flipper (0.21), the golden path is all handled by simply bundling the gems you need.

If this version had a name, it would probably be convention over configuration. I'm going to take you through all the automatic ✨ now. So read on and enjoy.

Automatic Adapters

In previous versions of Flipper, you had several decisions to make to get started:

  • Which adapter should I use? What even is an adapter?
  • Should I include memoization? How do I do that?
  • Should I preload all features, some features or no none?

No more. After more than a decade of using feature flags and eight years since the inception of Flipper, we have opinions on a default setup.

And this release makes all those choices for you.

First, drop this in your Gemfile and run bundle:

gem "flipper"

Now peel out. Yep, that's it. You are all setup and ready to sprinkle your code with power ✨. Flipper.enabled? and friends will just work™.

How you say? What is this dark ruby-licious magic? Wherever, whenever possible (like Shakira), Flipper now tries to do all the configuration for you (#502).

Now don't get too excited. That alone won't get you very far.

But it will automatically set you up with the memory adapter so you can kick the tires and get a feel for Flipper.

Choose Your Own Adventure

To get real work done, you have to pick from our vast array of adapters or roll your own. And that is where it starts to get hard, right? Wrong.

Oooooh hashtag burn. See how I set you up there. Sorry, I'll stop slinging the hash tags and just show you.

Let's say you pick redis to store your feature flag data:

gem "flipper-redis"

With that tiny addition (literally -redis) and another bundle, you are ready to rock and roll feature flags all the way to production.

It's the same story for many of our other supported adapters.

Active Record

gem "flipper-active_record
# create migration and migrate
$ rails g flipper:active_record && rails db:migrate

Sequel

gem 'flipper-sequel'
irb> require 'generators/flipper/templates/sequel_migration'
irb> CreateFlipperTablesSequel.new(Sequel::Model.db).up

Mongo

# set MONGO_URL
gem 'flipper-mongo'

Need other storage? Check out the full list of adapters or roll your own.

Automatic Memoization & Preloading

The great thing is we didn't only configure clients and connections for you. If you're using Rails, we'll now set you up with everything else you need for performant feature flags.

Flipper has long included memoization of feature data per request and preloading of that data (if you so desire). But to use either you had to add the memoizer middleware and configure it correctly.

Now, Flipper comes standard with a railtie that automatically turns on memoization and preloading. One less middleware to think about post-install. And a whole lot fewer network calls by default 📉.

The important thing about defaults is making them easy to change. So we did that too.

Tweaking Memoization

If you know what you are doing, you can disable memoization entirely:

Rails.application.configure do
  config.flipper.memoize = false
end

Or, just disable it for particular requests:

Rails.application.configure do
  config.flipper.memoize = ->(request) { 
    !request.path.start_with?("/assets") 
  }
end

Tweaking Preloading

You can preload only particular features (say the ones used on most requests):

Rails.application.configure do
  config.flipper.preload = [:stats, :search, :some_feature]
end

Or, you can disabling preloading entirely:

Rails.application.configure do
  config.flipper.preload = false
end

Again, all you've done is include one gem. And now you have feature flags that do only one network call on each request. No effort for you.

Automatic flipper_id

One of the minor annoyances has always been remembering to define flipper_id on any object that you'd like to enable or disable an actor for.

For this, Flipper now ships with Flipper::Identifier (source). Include this module in any object and you get a sweet default implementation of flipper_id.

class User
  include Flipper::Identifier
  
  attr_reader :id
  
  def initialize(id)
    @id = id
  end
end

User.new(1).flipper_id # => "User;1"

We also automatically include Flipper::Identifier for any Active Record or Sequel models (#505).

irb(main)> Feature.new(id: 1).flipper_id
=> "Feature;1"
irb(main)> Project.new(id: 1).flipper_id
=> "Project;1"
irb(main)> Organization.new(id: 1).flipper_id
=> "Organization;1"

We didn't want to litter the entire object space. But we thought at least these two models would be good additions.

Again, convention over configuration. If we can make a decision for you based on a best practice, then we will.

Automatic Cloud

I don't think that setup was much of a barrier to entry for Cloud.

What I'm hearing is current Flipper users (OSS) already have work arounds for some of the current problems Cloud solves. Or, they're concerned we'll impact their availability (hint: we won't, watch here and/or read on).

Regardless, while we were on this reduce friction mission, we made Cloud more automatic as well.

Superfluous Setting Removal

First, sticking with the theme of this release, we removed a superfluous setting (#511). If you have sync_method or FLIPPER_CLOUD_SYNC_METHOD configured, just ☠️ them.

FLIPPER_CLOUD_SYNC_SECRET now automatically switches Cloud's sync_method to :webhook negating the need for sync_method shennanigans.

Automatic Configure

Since we had automatic configuration of the bundled adapters, it seemed only right to make cloud automatically configure as well (#506).

Let's say you want to use Active Record for Flipper reads in your app with Cloud as the source of truth. Here you go:

gem "flipper-active_record"
$ rails g flipper:active_record && rails db:migrate
gem "flipper-cloud"
# set FLIPPER_CLOUD_TOKEN

That's it. Add the gems. Generate the tables for Active Record. Set the environment variable for Cloud. Done.

You want to use Redis for feature flag reads all controlled by Cloud?

No problem:

gem "flipper-redis"
gem "flipper-cloud"
# set FLIPPER_CLOUD_TOKEN

Whatever adapter you pick, Cloud automatically wraps it (here, here and here).

All reads in your app go to the local adapter you pick (isolating your app's availability from Cloud) and all writes go to Cloud and then the local adapter.

The result is your feature flag reads are blazing fast. But you get multi-environments, permissions, audit history and more from Cloud.

Automatic Webhooks

The aforementioned configuration would setup polling as the synchronization method with cloud. For production, we don't recommend polling. We want your app to be as isolated from Cloud as possible. It's just good architecture.

Instead, we provide webhooks that ping your app and tell it to sync with us. As of this release, Cloud automatically mounts the webhook middleware in your app if FLIPPER_CLOUD_TOKEN and FLIPPER_CLOUD_SYNC_SECRET are configured (#506).

🚨 I'm going to say that again. 🚨

Add two gems.

Add two environment variables.

And you can control your code without changing your code from anywhere.

It's huge folks.

Easy Upgrade

Unfortunately this section isn't automatic. You have to do something. But we made it as easy as we can.

The good news is upgrading the gem should just work™ in a backwards compatible way. 😅

The even better news is if you read over the changelog and follow our upgrade instructions, you'll likely get to remove a bunch of code (a good ol' 🩸 diff).

QA in the Wild

Knowing that this release changes a lot of guts, we battle tested it on Cloud itself, Box Out Sports, and Sailboat Guide prior to releasing to you.

They've all been upgraded for several days without any issues. We hope that our pain is your gain (and trust me there was pain making this smooth for you).

Wrap Up

That's it. We're pumped about this release. It takes simplicity and ease of use to the next level while retaining stability and compatibility.

If you aren't using feature flags yet, you have no reason not to. If you are already using flipper, upgrading should be easy.

Either way, let us know if you have any problems. Happy flipping!

P.S. If you like all of these changes, shout out to @bkeepers on twitter. This was all him. He tried out Cloud a month or so ago, put his pinky to the corner of his mouth and said "This could be simpler."

Making it simpler was a lot of hard work. But now it is.

If you enjoyed this post,
you should subscribe for more.