Resources are type-validated parameters that are passed to feature actions. Featury integrates with Servactory to provide robust resource validation and flexible parameter handling.
Use the resource method to define a parameter:
class User::OnboardingFeature < ApplicationFeature
prefix :user_onboarding
resource :user, type: User
feature :passage
endSpecifies the expected type of the resource. Featury uses Servactory for type validation:
resource :user, type: User
resource :account, type: Account
resource :comment, type: String
resource :count, type: IntegerPasses the resource as an option to the feature flag system:
class User::OnboardingFeature < ApplicationFeature
resource :user, type: User, option: true
feature :passage
action :enabled?, web: :enabled? do |features:, **options|
puts options.inspect
# => { user: #<User:0x00007f9b1c8b3e00> }
features.all? { |feature| Flipper.enabled?(feature, *options.values) }
# Calls: Flipper.enabled?(:user_onboarding_passage, user_instance)
end
end
User::OnboardingFeature.enabled?(user: user)Without option: true:
class User::OnboardingFeature < ApplicationFeature
resource :user, type: User
# option: true is NOT specified
feature :passage
action :enabled?, web: :enabled? do |features:, **options|
puts options.inspect
# => {}
# The user resource is NOT included in options
end
endUse option: true when your feature flag system needs the resource as a context parameter (e.g., Flipper actors).
Makes a resource optional:
class User::OnboardingFeature < ApplicationFeature
resource :user, type: User, option: true
resource :account, type: Account, option: true, required: false
feature :passage
end
# Can be called without :account
User::OnboardingFeature.enabled?(user: user)
# Or with :account
User::OnboardingFeature.enabled?(user: user, account: account)Use Cases:
- Global feature flags that don't require user context
- Optional context parameters for logging/analytics
- Features that work with or without certain resources
Passes the resource to nested groups:
class User::OnboardingFeature < ApplicationFeature
resource :user, type: User, option: true, nested: true
feature :passage
group BillingFeature
end
class BillingFeature < ApplicationFeature
resource :user, type: User, option: true
feature :api
end
User::OnboardingFeature.enabled?(user: user)
# The :user resource is passed to:
# 1. User::OnboardingFeature (for :user_onboarding_passage)
# 2. BillingFeature (for :billing_api)Without nested: true:
class User::OnboardingFeature < ApplicationFeature
resource :user, type: User, option: true
# nested: true is NOT specified
group BillingFeature
end
class BillingFeature < ApplicationFeature
resource :user, type: User, option: true
feature :api
end
# This will raise an error because BillingFeature expects :user
# but it's not passed from the parent
User::OnboardingFeature.enabled?(user: user)You can combine multiple options:
class MainFeature < ApplicationFeature
# Required resource, passed as option, passed to nested groups
resource :user, type: User, option: true, nested: true
# Optional resource, passed as option, not nested
resource :account, type: Account, option: true, required: false
# Required resource, not passed as option (only for validation)
resource :context, type: Hash
feature :main
group SubFeature
endFeatury uses Servactory for resource validation, which provides:
resource :user, type: User
User::OnboardingFeature.enabled?(user: "not a user")
# Raises Servactory validation errorYou can use Servactory's validation features:
resource :user, type: User, option: true
resource :age, type: Integer, option: true, required: falseFor more advanced validations, refer to the Servactory documentation.
class User::OnboardingFeature < ApplicationFeature
resource :user, type: User, option: true, nested: true
feature :passage
group BillingFeature
endUse this pattern when:
- Features are user-specific
- Nested groups need the same user context
- Using Flipper actors or similar
class OrganizationFeature < ApplicationFeature
resource :organization, type: Organization, option: true, nested: true
resource :user, type: User, option: true, nested: true
feature :admin_panel
group BillingFeature
endUse this pattern when:
- Features depend on multiple entities
- Both resources are needed for nested groups
class ExperimentalFeature < ApplicationFeature
resource :user, type: User, option: true, required: false
feature :beta_ui
end
# Can be called globally
ExperimentalFeature.enabled?
# Or for specific users
ExperimentalFeature.enabled?(user: user)Use this pattern when:
- Features can be enabled globally or per-user
- Managing progressive rollouts
class AnalyticsFeature < ApplicationFeature
resource :event_data, type: Hash # Not option: true
resource :user, type: User, option: true
feature :tracking
action :track, web: :regular do |features:, **options|
# event_data is validated but not in options
# Only user is in options
features.all? { |feature| Flipper.enabled?(feature, *options.values) }
end
endUse this pattern when:
- You need to validate a resource's type
- But don't need to pass it to the feature flag system
Resources are validated but not directly accessible in action blocks. Instead, they're passed via **options if marked with option: true:
class User::OnboardingFeature < ApplicationFeature
resource :user, type: User, option: true
resource :metadata, type: Hash # No option: true
action :enabled?, web: :enabled? do |features:, **options|
# options contains only :user (marked with option: true)
# metadata is validated but not included in options
user = options[:user]
features.all? { |feature| Flipper.enabled?(feature, user) }
end
endAccess resource definitions via .info:
class User::OnboardingFeature < ApplicationFeature
resource :user, type: User, option: true, nested: true
resource :account, type: Account, option: true, required: false
end
User::OnboardingFeature.info.resources.all
# Returns resource collection with type and option informationSee Info and Introspection for details.
- Learn about Conditions that use resources for conditional logic
- Review Actions to understand how resources flow to action blocks
- Explore Groups and the
nested: trueoption - See Examples for real-world resource patterns