feature-flags

Feature flags in Rails using the Flipper gem — boolean flags, percentage rollouts, per-user/group enablement, and UI. Use when doing canary releases, A/B testing, or gating features behind a flag.

rivettidaniel/vep-rails-agents1 installsMITSynced Aug 22

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: feature-flags
description: Feature flags in Rails using the Flipper gem — boolean flags, percentage rollouts, per-user/group enablement, and UI. Use when doing canary releases, A/B testing, or gating features behind a flag.
license: MIT
---

# Feature Flags with Flipper

## Overview

Feature flags decouple deployment from release. Ship code dark, enable for a subset, then roll out progressively.

| Use Case | Flipper Feature |
|----------|----------------|
| Enable for all users | `Flipper.enable(:feature)` |
| Enable for one user | `Flipper.enable_actor(:feature, user)` |
| Enable for a group | `Flipper.enable_group(:feature, :admins)` |
| Percentage of users | `Flipper.enable_percentage_of_actors(:feature, 10)` |
| Percentage of time | `Flipper.enable_percentage_of_time(:feature, 5)` |
| Disable entirely | `Flipper.disable(:feature)` |

## Setup

```ruby
# Gemfile
gem "flipper"
gem "flipper-active_record"  # DB-backed storage (recommended)
gem "flipper-ui"             # Admin UI (optional)

# Or for simple apps:
# gem "flipper-active_record" pulls in flipper automatically
```

```bash
bin/rails generate flipper:active_record
bin/rails db:migrate
```

```ruby
# config/initializers/flipper.rb
require "flipper"
require "flipper/adapters/active_record"

Flipper.configure do |config|
  config.adapter { Flipper::Adapters::ActiveRecord.new }
end

# Register groups
Flipper.register(:admins) { |actor| actor.respond_to?(:admin?) && actor.admin? }
Flipper.register(:beta_users) { |actor| actor.respond_to?(:beta?) && actor.beta? }
```

### Admin UI (optional)

```ruby
# config/routes.rb
Rails.application.routes.draw do
  mount Flipper::UI.app(Flipper) => "/flipper",
        constraints: AdminConstraint.new  # protect with auth
end

# app/constraints/admin_constraint.rb
class AdminConstraint
  def matches?(request)
    return false unless request.session[:user_id]
    User.find_by(id: request.session[:user_id])&.admin?
  end
end
```

## Checking Flags

### In controllers

```ruby
class BetaFeatureController < ApplicationController
  before_action :require_feature_flag

  def show
    # ...
  end

  private

  def require_feature_flag
    unless Flipper.enabled?(:new_dashboard, current_user)
      redirect_to root_path, alert: "Feature not available"
    end
  end
end
```

### In views

```erb
<% if Flipper.enabled?(:new_checkout, current_user) %>
  <%= render "checkout/new_flow" %>
<% else %>
  <%= render "checkout/legacy_flow" %>
<% end %>
```

### In service objects

Flag checks inside a service are fine — but side effects (mailers, jobs) stay in the controller:

```ruby
# ✅ Service only decides — no side effects
class Orders::CreateService < ApplicationService
  def call
    order = Order.create!(order_attributes)
    Success(order)
  end
end

# ✅ Controller handles the flag + side effects after result
class OrdersController < ApplicationController
  def create
    result = Orders::CreateService.call(user: current_user, params: order_params)

    if result.success?
      if Flipper.enabled?(:instant_confirmation, current_user)
        ConfirmationMailer.instant(result.value!).deliver_later
      else
        ConfirmationMailer.standard(result.value!).deliver_later
      end
      redirect_to result.value!
    else
      render_service_failure(result.failure)
    end
  end
end
```

### Shorthand helper (optional concern)

```ruby
# app/controllers/concerns/feature_flaggable.rb
module FeatureFlaggable
  extend ActiveSupport::Concern

  def feature_enabled?(flag)
    Flipper.enabled?(flag, current_user)
  end
  helper_method :feature_enabled?
end

# In view: <% if feature_enabled?(:new_dashboard) %>
```

## Managing Flags

### In console / seed / deployment

```ruby
# Enable globally
Flipper.enable(:dark_mode)

# Enable for a specific user
user = User.find(42)
Flipper.enable_actor(:dark_mode, user)

# Enable for admins group
Flipper.enable_group(:dark_mode, :admins)

# Canary: 5% of users
Flipper.enable_percentage_of_actors(:dark_mode, 5)

# Ramp up to 50%
Flipper.enable_percentage_of_actors(:dark_mode, 50)

# Full rollout
Flipper.enable(:dark_mode)

# Disable
Flipper.disable(:dark_mode)

# Check state
Flipper[:dark_mode].state        # :on / :off / :conditional
Flipper[:dark_mode].enabled?(user)
```

### Preloading flags to avoid N+1 in views

```ruby
# app/controllers/application_controller.rb
before_action :preload_feature_flags

private

def preload_feature_flags
  Flipper.preload([:new_dashboard, :new_checkout, :dark_mode])
end
```

## Actor Requirements

Flipper requires actors to respond to `flipper_id`:

```ruby
# app/models/user.rb
class User < ApplicationRecord
  # Flipper uses this as the unique actor identifier
  def flipper_id
    "User:#{id}"
  end
end
```

## Seeding Flags in Development

```ruby
# db/seeds.rb
# Ensure flags exist but don't override their state if already set
[
  :new_dashboard,
  :new_checkout,
  :dark_mode,
  :instant_confirmation
].each do |flag|
  Flipper.add(flag) unless Flipper.exist?(flag)
end

# Enable everything in development
if Rails.env.development?
  Flipper.enable(:new_dashboard)
  Flipper.enable(:new_checkout)
end
```

## Testing

```ruby
# spec/rails_helper.rb
RSpec.configure do |config|
  config.before(:each) do
    # Reset all flags between tests
    Flipper.instance_variable_set(:@adapter, nil)
    Flipper.configure { |c| c.adapter { Flipper::Adapters::Memory.new } }
  end
end
```

Flag behavior lives in the **controller**, not the service — test it with a request spec:

```ruby
RSpec.describe "Orders", type: :request do
  let(:user) { create(:user) }
  let(:valid_params) { { order: attributes_for(:order) } }

  before { sign_in user }

  context "when instant_confirmation flag is enabled" do
    before { Flipper.enable(:instant_confirmation) }

    it "sends instant confirmation email" do
      expect {
        post orders_path, params: valid_params
      }.to have_enqueued_mail(ConfirmationMailer, :instant)
    end
  end

  context "when instant_confirmation flag is disabled" do
    before { Flipper.disable(:instant_confirmation) }

    it "sends standard confirmation email" do
      expect {
        post orders_path, params: valid_params
      }.to have_enqueued_mail(ConfirmationMailer, :standard)
    end
  end
end
```

The service itself has no flag dependency — its spec tests only order creation:

```ruby
RSpec.describe Orders::CreateService do
  let(:user) { create(:user) }

  it "creates and returns the order" do
    result = described_class.call(user: user, params: attributes_for(:order))
    expect(result).to be_success
    expect(result.value!).to be_a(Order)
  end
end
```

## Checklist

- [ ] `flipper-active_record` in Gemfile + migration run
- [ ] Groups registered in initializer (`Flipper.register`)
- [ ] `flipper_id` defined on User model
- [ ] Admin UI mounted with auth constraint (never public)
- [ ] Flags preloaded in ApplicationController to prevent N+1
- [ ] Flags seeded in `db/seeds.rb` for development
- [ ] Tests use `Flipper::Adapters::Memory` (not ActiveRecord)
- [ ] Flags disabled / cleaned up after full rollout (no dead flags)

More Deployment & CI/CD skills

azure-enterprise-infra-planner

microsoft/azure-skills

Architect and provision enterprise Azure infrastructure from workload descriptions. For cloud architects and platform engineers planning networking, identity, security, compliance, and multi-resource topologies with WAF alignment. Generates Bicep or Terraform directly (no azd). WHEN: 'plan Azure infrastructure', 'architect Azure landing zone', 'design hub-spoke network', 'plan multi-region DR topology', 'set up VNets firewalls and private endpoints', 'subscription-scope Bicep deployment', 'Azure Backup for VM workloads'. PREFER azure-prepare FOR app-centric workflows.

387.5k

azure-kubernetes-app-deploy

microsoft/azure-skills

Use when deploying an existing web application or API to an already-running Azure Kubernetes Service cluster. Detects the framework, generates a Dockerfile and Kubernetes manifests, validates against AKS Deployment Safeguards, and deploys with verification. WHEN: deploy app to AKS, deploy to existing AKS cluster, containerize app for Kubernetes, generate K8s manifests for Azure, set up CI/CD for AKS, my AKS deployment is failing safeguard checks, I have a Django/Express/Spring Boot app to run on AKS. DO NOT USE FOR: creating or provisioning an AKS cluster (use azure-kubernetes), assessing migration to AKS Automatic (use azure-kubernetes-automatic-readiness), or deploying to non-AKS targets like Web Apps, Container Apps, or Functions.

380.4k

finetuning

microsoft/azure-skills

Fine-tune models on Microsoft Foundry using SFT (supervised), DPO (preference), or RFT (reinforcement with graders). Covers dataset preparation, training job submission, deployment, and evaluation. USE FOR: fine-tune, SFT, DPO, RFT, training data, grader, distillation, fine-tuned model, training job, large file upload, calibrate grader, deploy fine-tuned model, evaluate fine-tuned model. DO NOT USE FOR: general model deployment without fine-tuning (use deploy-model), agent creation (use agents), prompt optimization without training (use prompt-optimizer).

323.2k

← All Deployment & CI/CD skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY