Class: Subflag::Rails::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/subflag/rails/client.rb

Overview

Client for evaluating feature flags

This is the low-level client used by FlagAccessor. Most users should use Subflag.flags instead.

Instance Method Summary collapse

Instance Method Details

#enabled?(flag_key, user: nil, context: nil, default: false) ⇒ Boolean

Check if a boolean flag is enabled

Parameters:

  • flag_key (String)

    The flag key (already normalized)

  • user (Object, nil) (defaults to: nil)

    The user object for targeting

  • context (Hash, nil) (defaults to: nil)

    Additional context attributes

  • default (Boolean) (defaults to: false)

    Default value if flag not found (defaults to false)

Returns:

  • (Boolean)


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/subflag/rails/client.rb', line 53

def enabled?(flag_key, user: nil, context: nil, default: false)
  ctx = ContextBuilder.build(user: user, context: context)

  # Check prefetch cache first
  prefetched = get_prefetched_value(flag_key, ctx, :boolean)
  if !prefetched.nil?
    log_evaluation(flag_key, prefetched, default)
    return prefetched
  end

  cache_key = build_cache_key(flag_key, ctx, :boolean)

  result = RequestCache.fetch(cache_key) do
    openfeature_client.fetch_boolean_value(flag_key: flag_key, default_value: default, evaluation_context: ctx)
  end

  log_evaluation(flag_key, result, default)
  result
end

#evaluate(flag_key, user: nil, context: nil, default:) ⇒ EvaluationResult

Evaluate a flag and get full details - default is required

Parameters:

  • flag_key (String)

    The flag key (already normalized)

  • user (Object, nil) (defaults to: nil)

    The user object for targeting

  • context (Hash, nil) (defaults to: nil)

    Additional context attributes

  • default (Object)

    Default value (required - determines expected type)

Returns:

Raises:

  • (ArgumentError)

    If default is nil



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/subflag/rails/client.rb', line 110

def evaluate(flag_key, user: nil, context: nil, default:)
  ctx = ContextBuilder.build(user: user, context: context)

  # Check prefetch cache first - returns full EvaluationResult
  prefetched_result = get_prefetched_result(flag_key, ctx)
  if prefetched_result
    log_evaluation(flag_key, prefetched_result.value, default)
    return EvaluationResult.from_subflag(prefetched_result)
  end

  cache_key = build_cache_key(flag_key, ctx, "details:#{default.class}")

  details = RequestCache.fetch(cache_key) do
    fetch_details_by_type(flag_key, default, ctx)
  end

  log_evaluation(flag_key, details[:value], default)
  EvaluationResult.from_openfeature(details, flag_key: flag_key)
end

#prefetch_all(user: nil, context: nil) ⇒ Array<Hash>

Prefetch all flags for a user/context

Fetches all flags and caches them for subsequent lookups. Behavior varies by backend:

  • :subflag — Single API call to fetch all flags
  • :active_record — Single DB query to load all enabled flags
  • :memory — No-op (flags already in memory)

Examples:

Subflag::Rails.client.prefetch_all(user: current_user)
# Subsequent lookups use cache - no API calls
subflag_enabled?(:new_feature)

Parameters:

  • user (Object, nil) (defaults to: nil)

    The user object for targeting

  • context (Hash, nil) (defaults to: nil)

    Additional context attributes

Returns:

  • (Array<Hash>)

    Array of prefetched flag results (for inspection)



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/subflag/rails/client.rb', line 32

def prefetch_all(user: nil, context: nil)
  case configuration.backend
  when :subflag
    prefetch_from_subflag_api(user: user, context: context)
  when :active_record
    prefetch_from_active_record(user: user, context: context)
  when :memory
    # Already in memory, nothing to prefetch
    []
  else
    []
  end
end

#value(flag_key, user: nil, context: nil, default:) ⇒ Object

Get a flag value - default is required to determine type

Parameters:

  • flag_key (String)

    The flag key (already normalized)

  • user (Object, nil) (defaults to: nil)

    The user object for targeting

  • context (Hash, nil) (defaults to: nil)

    Additional context attributes

  • default (Object)

    Default value (required - determines expected type)

Returns:

  • (Object)

    The flag value

Raises:

  • (ArgumentError)

    If default is nil



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/subflag/rails/client.rb', line 81

def value(flag_key, user: nil, context: nil, default:)
  ctx = ContextBuilder.build(user: user, context: context)

  # Check prefetch cache first
  expected_type = type_from_default(default)
  prefetched = get_prefetched_value(flag_key, ctx, expected_type)
  if !prefetched.nil?
    log_evaluation(flag_key, prefetched, default)
    return prefetched
  end

  cache_key = build_cache_key(flag_key, ctx, default.class)

  result = RequestCache.fetch(cache_key) do
    fetch_value_by_type(flag_key, default, ctx)
  end

  log_evaluation(flag_key, result, default)
  result
end