flipper icon indicating copy to clipboard operation
flipper copied to clipboard

Add #flipper_enabled? to ActiveRecord models

Open bkeepers opened this issue 1 year ago • 5 comments

Adds #flipper_enabled? to all ActiveRecord models as shorthand for Flipper.enabled?(:feature_name, model)…with a bonus…

One thing that has always felt awkward is that I'm never quite sure who/what to use as an actor when building a new feature. Is it user-centric? Or some other other model like Organization or Project? In #710 we added the ability to check multiple actors at once, which is great, but it's still awkward to always have to have Flipper.enabled?(:feature, current_user, *current_user&.organizations) sprinkled throughout the code.

With this change, you can define #flipper_actors on any model, and calling #flipper_enabled? will check the feature against the relevant actors.

class User < ApplicationRecord
  has_many :memberships
  has_many :organizations, through: :memberships

  def flipper_actors
    [self] + organizations
  end
end

So now current_user.flipper_enabled?(:new_feature) will check if it's enabled for a specific user or any organization that they are part of.

bkeepers avatar Aug 30 '23 19:08 bkeepers

I'm not sure I understand.

I just meant if you have this:

class User < ApplicationRecord
  has_many :memberships
  has_many :organizations, through: :memberships

  def flipper_actors
    [self] + organizations
  end
end

class Organization < ApplicationRecord
  def flipper_actors
    [self] # no way to add user here so its the same multi actor as user
  end
end

user = User.find(...) # user is member of org
org = Org.find(...)
Flipper.enable(:foo, org)

user.feature_enabled?(:foo) # => true
org.feature_enabled?(:foo) # => true

Both of those work. But they are not symmetrical. If you enable user instead of org the result is different.

Flipper.disable(:foo, org)
Flipper.enable(:foo, user)

user.feature_enabled?(:foo) # => true
org.feature_enabled?(:foo) # => false

Looking at it, it only works as hierarchy and when using the lowest level. But if you check from higher levels you'll have to really know what's going on.

Maybe because users are a very common actor and usually the lowest level in a given hierarchy this will end up fine?

jnunemaker avatar Sep 15 '23 12:09 jnunemaker

Looking at it, it only works as hierarchy and when using the lowest level. But if you check from higher levels you'll have to really know what's going on.

Gotcha, I guess I see that as desired behavior. I often want to enable a feature for aUser (myself or specific users) before other actor models like Project or Organization. I also expect that enabling a feature for an Organization will enable it for all users in that organization.

bkeepers avatar Sep 15 '23 21:09 bkeepers

Interesting! Let’s decide on it next week. Only other concern is one more thing to search for when finding flag usage.

jnunemaker avatar Sep 15 '23 21:09 jnunemaker

Seeing #783 made me think if we do this PR we could also add flipper_features to return all enabled features for an actor or a Hash of all features with key pointed at true/false.

jnunemaker avatar Dec 09 '23 16:12 jnunemaker

@bkeepers I was going through old PRs today. I say we merge this and see if people like it.

jnunemaker avatar Jan 03 '24 22:01 jnunemaker