Rails Integration
The toggly-rails gem provides deep integration with Ruby on Rails applications.
Features
- Railtie: Auto-configuration and initialization
- Controller Concern:
feature_enabled?helper method - View Helpers: Canonical
featureblocks with optional negation - Middleware: Request-scoped context management
- Generators: Easy setup with
rails generate - Rake Tasks: Command-line management tools
- Testing Helpers: RSpec and Minitest integration
Installation
gem 'toggly-rails'
bundle install
rails generate toggly:install
Requirements
toggly-rails requires Ruby 3.2+ and Rails 7.0+. The retained Rails hosts are 7.0.10, 7.1.6, 7.2.3.2, and 8.0.5.1. Rails 8.1.3.1 is also verified with Ruby 4.0.6. Use a Ruby version supported by the Rails release you select, and let Bundler record the resolved versions in your application's Gemfile.lock.
Configuration
Basic Setup
Toggly::Rails.configure do |config|
config.app_key = Rails.application.credentials.dig(:toggly, :app_key)
config.environment = Rails.env.production? ? 'Production' : 'Staging'
config.defaults = { 'ExpressCheckout' => false, 'new_dashboard' => false }
end
Using Credentials
rails credentials:edit
toggly:
app_key: your-app-key
environment: Production
The Railtie auto-configures from nested credentials.toggly only if no Rails configuration exists. Prefer the explicit initializer above when you need defaults: without a key, nonempty defaults select offline mode. A missing key with empty defaults raises Toggly::ConfigError. Configure once; repeated configuration replaces the global client without closing the old one. The Railtie closes the process client at exit.
Add the complete request builder inside that initializer for claims and HTTP filters. Default mapping supplies identity/groups/traits/entity only. The examples below assume your application already authenticates current_user.
Controller Integration
Basic Usage
class ProductsController < ApplicationController
def index
if feature_enabled?(:new_product_list)
@products = Product.includes(:images, :reviews).all
render :index_v2
else
@products = Product.all
end
end
end
Require Feature (Gate)
class AdminController < ApplicationController
before_action :require_admin_features
private
def require_admin_features
require_feature!(:admin_panel) # Returns 404 if disabled
end
end
Custom Context
The SDK's before-action caches toggly_context. Load the authenticated user and authorized entity before that first build. Here current_user.orders is your application association limiting access to the user's Orders; adapt it to your authorization model.
class OrdersController < ApplicationController
prepend_before_action :load_toggly_order
def show
render json: { express: feature_enabled?('ExpressCheckout') }
end
private
def load_toggly_order
# Authentication must already have run before this callback.
order = current_user.orders.find(params[:id])
request.env['toggly.entity'] = Toggly::EntityContext.new(
kind: 'Order', key: order.id.to_s,
attributes: { 'Vip' => order.vip?, 'Total' => order.total.to_f }
)
end
end
For another authorized Order in the same action, create other_entity the same way, then call feature_enabled?('ExpressCheckout', context: toggly_context.with_entity(other_entity)). Changing request.env after context is cached does not rebuild it. To replace the whole request context, use self.toggly_context = new_context before evaluation. Never change identity on a shared process client.
Override Current User
authenticate_api_token below is your application authentication method, returning a verified principal:
class ApiController < ApplicationController
protected
def toggly_current_user
@api_user ||= authenticate_api_token
end
end
The gate returns 404 when disabled. HTML responses require the host application's public/404.html; JSON uses the adapter's JSON response. Feature gates complement your normal authentication and authorization.
View Helpers
Basic Checks
<%= feature(:new_header) do %>
<%= render 'new_header' %>
<% end %>
<%= feature(:new_header, negate: true) do %>
<%= render 'header' %>
<% end %>
Block Helpers
<% context = toggly_context %>
<%= feature(:promo_banner, context: context) do %>
<div class="promo">
<h2>Special Offer!</h2>
<p>Get 20% off today!</p>
</div>
<% end %>
<%= feature(:promo_banner, context: context, negate: true) do %>
<p>Standard offer</p>
<% end %>
Both blocks must use the same feature key and context. feature evaluates
through feature_enabled?, then ActionView captures only the selected block.
negate: true selects the complementary branch.
when_feature_enabled(feature_key, context: nil) and
when_feature_disabled(feature_key, context: nil) remain available as
deprecated compatibility adapters to positive and negated feature calls.
The boolean feature_enabled? / feature_disabled? helpers are unchanged.
Feature Switch
<%= feature_switch(:new_button,
enabled: content_tag(:button, 'New Style', class: 'btn-new'),
disabled: content_tag(:button, 'Classic', class: 'btn-classic')
) %>
Middleware
The Railtie installs the native middleware, controller concern and view helpers. The controller concern builds the request context; the middleware clears its toggly.context and toggly.current_user entries before and after each request, including errors. Application-owned toggly.entity belongs in that request's env; initialize/clear it yourself if your host reuses env hashes.
Accessing Request Context
# In a controller
def show
context = toggly_context
# Context built from current_user and request
end
Disabling Request Context
Inside your existing startup configuration block:
config.request_context_enabled = false
This disables automatic before-action context setup, not the explicit context helpers. Supply context explicitly when needed.
Rake Tasks
List Features
rake toggly:list
Illustrative output (actual flags and counts depend on your app):
Feature Flags (5):
------------------------------------------------------------
dark-mode ✓ enabled
new-checkout ✗ disabled
premium-features ✓ enabled
beta-ui ✓ enabled
maintenance-mode ✗ disabled
Check Specific Feature
rake toggly:check[dark-mode]
# Feature 'dark-mode' is ENABLED
Refresh Definitions
rake toggly:refresh
# Successfully refreshed 5 features
Show Configuration
rake toggly:config
Illustrative output (actual flags and counts depend on your app):
Toggly Configuration:
----------------------------------------
App Key: abc12345...
Environment: Production
Base URL: https://definitions.toggly.io/
Refresh Interval: 300s
Request Context: enabled
Rails Cache: disabled
Client Status:
Ready: yes
Features: 5
Rails Caching
Inside the existing initializer, use Rails.cache for definition snapshots:
config.use_rails_cache = true
config.cache_key_prefix = "shop:#{config.environment}:toggly"
Give each app/environment its own prefix. A snapshot stores definitions, not a user's evaluated results. Startup loads it and still attempts a network fetch; it does not guarantee nonblocking startup or synchronized decisions across processes. See Caching.
API Endpoints
For an application endpoint, derive identity and claims from the authenticated principal and load only authorized entities, using the controller pattern above. Return the feature keys your client needs. Do not accept arbitrary user_id, groups or claims parameters as trusted evaluation context; the SDK does not authenticate those values.
Best Practices
1. Environment-Based Configuration
Merge into the existing startup configuration block:
case Rails.env
when 'production'
config.environment = 'Production'
config.refresh_interval = 60
when 'staging'
config.environment = 'Staging'
config.refresh_interval = 30
else
config.environment = 'Development'
config.enable_undefined_in_dev = false
config.disable_background_refresh = true
end
2. Fail-Safe Defaults
config.defaults = {
'critical-checkout-flow' => true,
'maintenance-mode' => false
}
3. Logging
The Rails adapter supplies Rails.logger; there is no Rails configuration logger setter.
4. Testing
# In the existing initializer; also omit the key and supply nonempty test defaults.
config.disable_background_refresh = Rails.env.test?
See Testing for deterministic offline setup and the Ruby Rails SDK sample for a runnable application using the native Railtie, controller and view helpers, request context and Order evaluation.