Skip to content

Instantly share code, notes, and snippets.

@kaspth
Created July 4, 2024 11:37
Show Gist options
  • Save kaspth/a4ce728acfe0b1d02b6af4bdbf6e440b to your computer and use it in GitHub Desktop.
Save kaspth/a4ce728acfe0b1d02b6af4bdbf6e440b to your computer and use it in GitHub Desktop.
Playing around with one central location to define Feature flags using `Current` as the backing.
# app/models/feature.rb
module Feature
include Flipper::Context
flag :like # Assumed to be via: :user
flag :soon_to_ship_cool_feature, via: :account
end
module Flipper::Context
def self.included(klass) = klass.extend(ClassMethods, self)
module ClassMethods
# Feature.like.enabled? # or Feature.like?
def flag(*keys, via: :user)
keys.each do |key|
define_method(key) { Flag.new(key, via) }
define_method("#{key}?") { enabled?(key) }
end
end
end
class Flag < Data.define(:key, :via)
# Relies on Current.user or Current.account and then the context being read as late as possible
def enabled? = Flipper.enabled?(key, Current.public_send(via))
def disabled? = !enabled?
# Allow Flags to be used as routing constraints, e.g.:
# resources :likes, only: %i[create destroy], constraints: Feature.like
# (haven't tested this yet)
def matches?(request) = enabled?
end
# For dynamic keys, like in requires_feature
def enabled?(key) = public_send(key).enabled?
def disabled?(key) = public_send(key).disabled?
end
def self.requires_feature(key, **)
before_action(**) { head :bad_request unless Feature.enabled?(key) }
end
class LikesController < ApplicationController
requires_feature :like
# requires_feature :like, except: :destroy
def create
@like = Like.create(like_params)
redirect_to @like.article
end
def destroy
@like = Like.find(params[:id]).tap(&:destroy)
redirect_to @like.article
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment