Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for enabled features based on attribute values #157

Closed
jhubert opened this issue Sep 11, 2016 · 4 comments
Closed

Support for enabled features based on attribute values #157

jhubert opened this issue Sep 11, 2016 · 4 comments

Comments

@jhubert
Copy link

jhubert commented Sep 11, 2016

Groups are nice and powerful but they are limited to predefined rules. It would be really great to be able to do something like:

Flipper.attribute_gate { |data, thing| data[:values].include?(thing.send(data[:method])) }

This would allow features to be enabled or disabled on the fly based on granular attributes. For example, a feature that is on for all users who have en-US as their locale or who are members of a specific organization.

We have a multi-tenant application and a lot of times features are on for certain tenants but creating a group for each tenant seems excessive.

@jhubert jhubert changed the title Feature Request: Support for enabled features based on attribute values Support for enabled features based on attribute values Sep 11, 2016
@jhubert
Copy link
Author

jhubert commented Sep 11, 2016

@jnunemaker How do you handle features by organization in GitHub? For example, enabled if the user is in this organization and they are in this group.

@jnunemaker
Copy link
Collaborator

@jhubert hi! This reminds me of #51 a bit.

I definitely want to come up with a way of supporting usage like this. I've been working on some behind the scenes adapter stuff that I hope will make it easier to store "extra" data like this easily. The next issue would be exposing it in a way that makes sense, kind of like what you have for attribute_gate. I started a context branch a while back that I could probably merge which would help with this, once the adapter changes are done.

The crux of the context branch is that the group blocks get two parameters (actor, context) instead of one (actor).

Flipper.register(:enabled_team_member) do |actor, context|
  # split up Team:12 to ["Team", "12"]
  combos = context.values.actors.map { |flipper_id| flipper_id.split(":", 2) }
  team_names = combos.select { |class_name, id| class_name == "Team" }.map { |class_name, id| id }
  teams = team_names.map { |name| Team.find(name) }
  teams.any? { |team| team.member?(actor) }
end

I can get this merged, but this alone probably isn't enough. As you mentioned, you need a bit more data stored at the time of enable, it sounds like.

For example, a feature that is on for all users who have en-US as their locale or who are members of a specific organization.

Not ideal for you, but what do you think about storing this data outside of flipper for the time being? Perhaps something like below would work for now?

Flipper.register(:locale_org_enabled_members) do |actor|
  if actor.respond_to?(:locale) && actor.local == "en-US" # or whatever
    # locale_enabled_member? would get the orgs for the actor and check if any where local enabled, which could be attribute on org or stored in separate table
    Org.locale_enabled_member?(actor) }
  end
end

flipper.enable_group :locale_org_enabled_members
flipper.enabled?(some_actor) # would be true if actor had en-US locale and was in 

We have a multi-tenant application and a lot of times features are on for certain tenants but creating a group for each tenant seems excessive.

Yeah, multi-tenant does make things interesting. One idea that comes to mind is flipper instance per tenant. That would involve ensuring the tables exist for each tenant and some other bookkeeping though. That is probably my best idea based on the information you provided above. If you have any more specific examples, maybe I could try to come up with something else, or perhaps the examples I dropped above are sparking something for you?

How do you handle features by organization in GitHub? For example, enabled if the user is in this organization and they are in this group.

We typically either turn the feature on for everyone in the org or no one. For example, if we have "some new feature", the org might be an actor we pass to enabled?(org) to check to see if "some new feature" is enabled. I can't think of an instance where we wanted something enabled only for certain users in an org to date.

@jnunemaker
Copy link
Collaborator

I merged the context changes I mentioned, which allows doing things like this.

@jnunemaker
Copy link
Collaborator

@jhubert We are going to add shortcuts for a lot of the stuff shown below (and the syntax is not finalized yet).

But you'll be able to do something like this soon which solves your 5 year old problem (FINALLY!). 😆

for all users who have en-US as their locale or who are members of a specific organization

class User
  def flipper_properties
    {
      locale: "en-US",
      org_id: ...,
      # ...
    }
  end
end

Flipper.enable Flipper::Rules::Any.new(
  # en-US
  Flipper::Rules::Condition.new(
    {"type" => "property", "value: "local"},
    {"type" => "operator", "value: "eq"},
    {"type" => "string", "value: "en-US"}
  ),
  Flipper::Rules::Condition.new(
    {"type" => "property", "value: "org_id"},
    {"type" => "operator", "value: "in"},
    {"type" => "array", "value: [ ... ] } # array of org ids or something
  )
)

Closing this in favor of #157 which should solve this. Follow that issue to know when this gets released.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants