The Ruby on Rails experts
Logo_144 ClearCove Software, Inc. Rails Recipes

Sometimes you need to dynamically enable certain app features for a given user. This recipe gives you nice helper methods that you can add to controllers and views to guard features that should only be available to a subset of users:

First define the feature flag helper methods in a module.

# app/concerns/feature_flags.rb
module FeatureFlags

  def can_apply_advanced_ai?
    is_staff? || is_beta_tester?
  end

  # define any other helper methods ...

end

Include the module in your User class to add the feature flag helper methods to the current_user instance.

# app/models/user.rb
class User < ActiveRecord::Base

  # Add feature flag methods to user instances
  include FeatureFlags

  ...

end

Make the feature flag helper methods available to all controller actions and views. Delegate to current_user for easier referencing and to make it work if no current_user is present.

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base

  # Dynamically get a list of all implemented feature flags
  feature_flags = FeatureFlags.public_instance_methods
  # Delegate all feature flag methods to current_user
  delegate *feature_flags, :to => current_user, :allow_nil => true
  # Make feature flag methods available in views
  helper_method feature_flags

  ...

end

Guard features with conditionals that reference feature flag helper methods. Notice that you don't need to send these messages to current_user. They are automatically delegated to current_user with the directive in ApplicationController.

<%# app/views/users/index.html.erb %>
<h1>Users</h1>
...
<% if can_apply_advanced_ai? %>
  <li><%=# ... do some crazy advanced AI here ... %></li>
<% end %>
...

This recipe allows you to test new features internally and when you're ready to launch, all you do is to update the feature flag method to return true so that everybody will see the new feature. Then in a next step you can remove the feature flag helper method and all guard clauses in the views.

Credits

This recipe is inspired by Brandon Keepers' talk about Ruby at Github (about 3/4 through the presentation).