Posted July 27, 2020

Powerful feature flags in Ruby

Feature flags enable a powerful continuous delivery process and provide a platform for progressive delivery with phased rollouts and A/B tests.

Asa Schachar
Asa Schachar
Ruby Feature Flags

However, building a feature flagging system is usually not your company’s core competency and can be a distraction from other development efforts.

I’m Asa, Developer Advocate at Optimizely. In this step-by-step blog post, I’ll show you how to easily get set up and running with Optimizely Rollouts, a free product that allows you to roll out a feature one customer at a time without distracting from other development efforts.

Create a Ruby Application

If you already have a Ruby application feel free to skip to the next section “Steps to rollout a feature” below. Otherwise, follow the instructions to start a new Ruby Sinatra application:

Create a file called `myapp.rb` and paste the following contents:

# myapp.rb require 'sinatra' get '/' do 'Hello world!' end

Install the Sinatra ruby gem on the command-line with:

gem install sinatra

Run the application from the command-line with:

ruby myapp.rb

Find the port number that is displayed by your running server

[2020-06-11 14:29:43] INFO WEBrick::HTTPServer#start: pid=37152 port=4567

Open a browser to see your server running at http://localhost:4567 with the message “Hello World!”:

graphical user interface, text, application, email

Steps to rollout a feature

1. Setup the Feature Flag Interface

Create a free Optimizely Rollouts account here.

In the Rollouts interface, navigate to ‘Features > Create New Feature’ and create a feature flag called ‘hello_world’.

To connect your ‘hello_world’ feature to your Ruby application, find your SDK Key. Navigate to the far left ‘Settings’ > ‘Environments’ and copy the development SDK Key value. You can save the production SDK Key for when you’re ready to deploy your changes to production.

2. Install the Optimizely Rollouts Ruby SDK

Installing the Optimizely Ruby SDK allows you to setup feature toggles from within your Ruby application.

Install the Optimizely gem from the command-line with:

gem install optimizely-sdk

Create a new file optly.rb in the root of your new application. If you followed the Sinatra instructions above, the optly.rb file should be in the same directory as myapp.rb

Import the SDK and initialize a singleton instance of the Optimizely SDK by placing the following code in your new optly.rb file (be sure to replace <Your_SDK_Key> in the initialize function with your actual SDK key):

# optly.rb require 'singleton' require 'logger' require 'optimizely/optimizely_factory' class Optly include Singleton def initialize sdk_key = '<Your_SDK_Key>' logger = Optimizely::SimpleLogger.new(Logger::INFO) config_manager = Optimizely::HTTPProjectConfigManager.new( sdk_key: sdk_key, polling_interval: 10, blocking_timeout: 10, logger: logger, ) @client = Optimizely::OptimizelyFactory.custom_instance( sdk_key, # sdk_key nil, # datafile nil, # event_dispatcher logger, # logger nil, # error_handler false, # skip_json_validation nil, # user_profile_service config_manager, # config_manager nil # notification_center ) end def client @client end end

A singleton as we defined it above allows you to use Optimizely anywhere within your Ruby application you want, while ensuring your application is using the same instance of Optimizely.

Require the Optimizely singleton instance in your Ruby application by adding `require ‘./optly’` in `myapp.rb`:

# myapp.rb require 'sinatra' require './optly' # Imports the Optimizely singleton get '/' do 'Hello world!' end

3. Implement the Feature Flag

To implement your ‘hello_world’ feature flag, use the is_feature_enabled method on the optimizely client instance:

enabled = Optly.instance.client.is_feature_enabled('hello_world', 'user123', { 'customerId' => 123, 'isVIP' => true }) enabled ? 'Hello World! You got the hello_world feature!' : 'You did not get the hello_world feature'

Note that `is_feature_enabled` takes three parameters. The first is used to identify the feature you created in the Optimizely application. The next two are associated with visitors to your application:

  • userId: a string you provide that the Optimizely SDK uses for random percentage rollouts across your users. This can be any string that uniquely identifies users.
  • userAttributes: a hash of key, value attributes used for targeting rollouts across your users. You will use the `customerId` attribute to target your feature to specific groups of users starting in step 5. The `isVip`attribute is included as an additional example of how you may have multiple attributes of your users you want to target based off of.

To read more about the API and its parameters, see this documentation page.

Your full code in `myapp.rb` should look like the following:

# myapp.rb require 'sinatra' require './optly' get '/' do enabled = Optly.instance.client.is_feature_enabled('hello_world', 'user123', { 'customerId' => 123, 'isVIP' => true }) enabled ? 'Hello World! You got the hello_world feature!' : 'You did not get the hello_world feature' end

4. Turn the Feature Toggle on!

If you save and re-run your application now, you’ll notice that you did not get the feature. This is because the feature is not enabled, which means it’s off for all visitors to your application.

To turn on the feature:

  1. Log-in to the Optimizely project where you made your hello_world feature
  2. Navigate to Features
  3. Click on the ‘hello_world’ feature
  4. Change to the ‘Development’ environment to match the SDK Key we used
  5. Roll the feature out to ensure it is set to 100% for everyone
  6. Click Save to save your changes

In less than 1 min, refreshing your Ruby app should now show the feature toggled on and you should see “Hello world! You got the hello_world feature!”.

5. Create an attribute for customerId

To target your feature based on the userAttributes you provided to the third parameter of is_feature_enabled in step 3, you’ll have to create those userAttributes in the Optimizely Application. Do that with the attribute ‘customerId’ to start:

  1. Log-in to the Optimizely project where you made your hello_world feature
  2. Navigate to Audiences -> Attributes
  3. Click ‘Create New Attribute…’
  4. Name the attribute key ‘customerId’
  5. Click ‘Save Attribute’ to save your changes

6. Create a beta audience 

Now let’s create an audience to indicate which customerIds should get access to your feature. This allows you to show the feature only to a group of beta users.

  1. Navigate to Audiences
  2. Click ‘Create new audience’
  3. Name the Audience ‘[hello_world] Beta Users’
  4. Drag and Drop your customerId attribute into the Audience conditions
  5. Change the ‘has any value’ drop-down to “Number equals” with the value 123 
  6. Click ‘Save Audience’

6. Add a rollout rule for the beta audience 

To use the audience in our feature rollout, we’ll add a rollout rule to our feature rollout.

  1. Navigate to Features
  2. Click on your ‘hello_world’ feature
  3. Change the environment to “Development” to match the SDK Key we copied in step 1.
  4. Click the ‘Search and add audiences’ input box
  5. Add the ‘[hello_world] Beta Users’ audience
  6. Click ‘Save’ to save changes to the rollout

Now you have individual controls of the feature for each audience.

To enable your feature only to your beta audience, roll the feature out to 100% for the ‘[hello_world] Beta Users’ and 0% for ‘Everyone’ else in your Development environment. Save your changes.

At this point your feature is only showing for customers with the customerId 123, which is what you provided to is_feature_enable method in step 3.

As a test to verify, you can change who is in the beta audience.

  1. Use the far left navigation to navigate to the Audiences dashboard
  2. Click the ‘[hello_world] Beta Users” Audience
  3. Change the customer id from 123 to 456
  4. Save your changes

In less than 1 min, refresh your browser showing the running Ruby application and watch as the feature will get turned off because you don’t meet the targeting conditions.

8. Add users to the beta

To add more customers into your beta audience, edit the audience definition to add or remove users from the beta:

  • Click on the “+” sign and save to add beta users
  • Click on the “x” sign and save to remove beta users

In the following gif example, three customers have been added to the beta. Customers with ids: 123, 456, and 789, will now have access to the ‘hello_world’ feature.

9. Launch the feature

After enabling your feature for enough customers to enjoy the new user experience, you may decide that it’s safe to launch your feature to all customers.

Once you are ready to launch your feature out of beta, follow these steps:

  1. Roll out the feature to 100% for Everyone
  2. Click the ‘X’ to delete the rule for the beta audience
  3. Save your changes

The feature is now available to everyone and you have successfully rolled out the ‘hello_world’ feature one customer at a time using free feature flags from Optimizely Rollouts in Ruby!

Next Steps

Although this blog covered customer-by-customer rollouts, feature flags enable additional use cases like not relying on long-lived feature branches, creating a permissioning system, or enabling product-driven A/B testing.

At Optimizely, we use feature flags for all of these use cases and more!

Hope this was helpful! Give feedback if you have any. I hope I’ve been successful in saving some of your team’s development resources by enabling you to harness the power of feature flags with our free feature flagging offering: Optimizely Rollouts.