feature_flags 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +11 -2
- data/app/controllers/feature_flags_controller.rb +16 -5
- data/app/views/feature_flags/_form.html.erb +21 -0
- data/app/views/feature_flags/_options.html.erb +8 -0
- data/app/views/feature_flags/edit.html.erb +1 -22
- data/app/views/feature_flags/index.html.erb +6 -0
- data/app/views/feature_flags/new.html.erb +1 -22
- data/lib/feature_flags.rb +4 -0
- data/lib/feature_flags/feature_base.rb +53 -0
- data/lib/feature_flags/manage_features.rb +40 -25
- data/lib/feature_flags/storage.rb +11 -0
- data/lib/feature_flags/version.rb +1 -1
- data/lib/generators/feature_flags/install_generator.rb +2 -0
- data/lib/generators/feature_flags/templates/feature_flag_migrate.rb +0 -1
- data/lib/generators/feature_flags/templates/feature_flag_model.rb +8 -2
- metadata +7 -4
data/README.md
CHANGED
@@ -18,8 +18,11 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
For more info:[Click Here](http://ror-tech.blogspot.in/2013/08/manage-different-features-in-our-ruby.html)
|
22
|
+
|
23
|
+
###For changes in new version(0.1.0):[Click Here](http://ror-tech.blogspot.com/2014/01/ruby-gem-featureflags-new-features-010.html)
|
22
24
|
|
25
|
+
with feature_flags gem you can easily manage different features in your rails application.You can turn on/off features.
|
23
26
|
|
24
27
|
rails generate feature_flags:install
|
25
28
|
|
@@ -35,6 +38,10 @@ then do
|
|
35
38
|
##############################################################################
|
36
39
|
FeatureFlags.enabled?(:feature_name) To check whether particular feature is enabled or not
|
37
40
|
|
41
|
+
FeatureFlags.enabled?([:feature_name1, :feature_name2, :feature_name3]) To check for multiple features
|
42
|
+
|
43
|
+
FeatureFlags.enabled_any?([:feature_name1, :feature_name2, :feature_name3]) To check if any of given features are enabled or not
|
44
|
+
|
38
45
|
FeatureFlags.enable_all To enable all features in your app.
|
39
46
|
|
40
47
|
FeatureFlags.disable_all To disable all features in your app.
|
@@ -43,7 +50,7 @@ then do
|
|
43
50
|
|
44
51
|
FeatureFlags.create_and_enable(:feature_name) To create and enable feature
|
45
52
|
|
46
|
-
FeatureFlags.enable(feature_name) To enable feature
|
53
|
+
FeatureFlags.enable(:feature_name) To enable feature
|
47
54
|
|
48
55
|
##############################################################################
|
49
56
|
|
@@ -60,6 +67,8 @@ If you want to generate views use,
|
|
60
67
|
rails generate feature_flags:views
|
61
68
|
|
62
69
|
|
70
|
+
For Demo:[Click Here](http://feature-flags.herokuapp.com/)
|
71
|
+
|
63
72
|
Here are some screenshots,
|
64
73
|
main index view
|
65
74
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
class FeatureFlagsController < ApplicationController
|
2
2
|
layout FeatureFlags.configuration.layout.downcase
|
3
|
+
before_filter :load_features, :only => [:index,:create,:update,:destroy]
|
3
4
|
|
4
5
|
def index
|
5
|
-
@features = Feature.all
|
6
6
|
end
|
7
7
|
|
8
8
|
def new
|
@@ -14,7 +14,6 @@ class FeatureFlagsController < ApplicationController
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def create
|
17
|
-
@features = Feature.all
|
18
17
|
@feature = Feature.new(params[:feature])
|
19
18
|
respond_to do |format|
|
20
19
|
if @feature.save
|
@@ -31,12 +30,21 @@ class FeatureFlagsController < ApplicationController
|
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
33
|
+
def enable_all
|
34
|
+
FeatureFlags.enable_all
|
35
|
+
end
|
36
|
+
|
37
|
+
def disable_all
|
38
|
+
FeatureFlags.disable_all
|
39
|
+
end
|
40
|
+
|
34
41
|
def update
|
35
|
-
@features = Feature.all
|
36
42
|
feature = Feature.find(params[:id])
|
43
|
+
enabled_all = params[:enable_all].present? ? enable_all : false
|
44
|
+
disabled_all = params[:disable_all].present? ? disable_all : false
|
37
45
|
|
38
46
|
respond_to do |format|
|
39
|
-
if feature.update_attributes(params[:feature])
|
47
|
+
if enabled_all || disabled_all || feature.update_attributes(params[:feature])
|
40
48
|
flash[:notice] = "#{feature.name} feature successfully updated"
|
41
49
|
format.html{
|
42
50
|
redirect_to feature_flags_url
|
@@ -58,7 +66,6 @@ class FeatureFlagsController < ApplicationController
|
|
58
66
|
end
|
59
67
|
|
60
68
|
def destroy
|
61
|
-
@features = Feature.all
|
62
69
|
feature = Feature.find(params[:id])
|
63
70
|
|
64
71
|
respond_to do |format|
|
@@ -82,4 +89,8 @@ class FeatureFlagsController < ApplicationController
|
|
82
89
|
end
|
83
90
|
end
|
84
91
|
end
|
92
|
+
|
93
|
+
def load_features
|
94
|
+
@features = Feature.all
|
95
|
+
end
|
85
96
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%= form_for feature, :url => path, :method => method, :html => {:class => "feature-flag-form"} do |f| %>
|
2
|
+
<div class ="field">
|
3
|
+
<label>Name : </label> <br/>
|
4
|
+
<%= f.text_field :name %>
|
5
|
+
<div class ="errors">
|
6
|
+
<% if feature.errors.any? %>
|
7
|
+
<% feature.errors.full_messages.each do |error| %>
|
8
|
+
<%= error %>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
</div>
|
14
|
+
<div class ="field">
|
15
|
+
<label>Status : </label>
|
16
|
+
<%= f.check_box :status %><label>Enabled </label> <br/>
|
17
|
+
</div>
|
18
|
+
<div class ="field">
|
19
|
+
<%= f.submit "Submit" %>
|
20
|
+
</div>
|
21
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= form_for feature, :url => feature_flag_url(feature), :method => :put, :html => {:class => "feature-flag-form",:style => "float:right;margin-right: 10px;display: inline-block"} do |f| %>
|
2
|
+
<%= hidden_field :enable_all,:value=> true %>
|
3
|
+
<%= f.submit "Enable All" %>
|
4
|
+
<% end %>
|
5
|
+
<%= form_for feature, :url => feature_flag_url(feature), :method => :put, :html => {:class => "feature-flag-form",:style => "float:right;margin-right: 10px;display: inline-block"} do |f| %>
|
6
|
+
<%= hidden_field :disable_all,:value=> false %>
|
7
|
+
<%= f.submit "Disable All" %>
|
8
|
+
<% end %>
|
@@ -7,26 +7,5 @@
|
|
7
7
|
|
8
8
|
<div class="feature-div">
|
9
9
|
<p style="font-weight:bold;font-size:23px">Update Feature</p>
|
10
|
-
<%=
|
11
|
-
<div class ="field">
|
12
|
-
<label>Name : </label> <br/>
|
13
|
-
<%= f.text_field :name %>
|
14
|
-
<div class ="errors">
|
15
|
-
<% if @feature.errors.any? %>
|
16
|
-
<% @feature.errors.full_messages.each do |error| %>
|
17
|
-
<%= error %>
|
18
|
-
<% end %>
|
19
|
-
<% end %>
|
20
|
-
</div>
|
21
|
-
|
22
|
-
</div>
|
23
|
-
<div class ="field">
|
24
|
-
<label>Status : </label>
|
25
|
-
<%= f.check_box :status %><label>Enabled </label> <br/>
|
26
|
-
</div>
|
27
|
-
<div class ="field">
|
28
|
-
<%= f.submit "Submit" %>
|
29
|
-
</div>
|
30
|
-
<% end %>
|
31
|
-
|
10
|
+
<%= render :partial => "/feature_flags/form" , :locals => {:path => feature_flag_path(@feature),:method =>:put,:feature => @feature } %>
|
32
11
|
</div>
|
@@ -14,7 +14,9 @@
|
|
14
14
|
|
15
15
|
</div>
|
16
16
|
<%= link_to "Add new Feature", new_feature_flag_path ,:style=>"float:right;margin-right: 50px;" %>
|
17
|
+
<%= render :partial => "/feature_flags/options", :locals => { :feature => @features.last } if @features.any?%>
|
17
18
|
|
19
|
+
<!--list of features start-->
|
18
20
|
<div class="feature_flag">
|
19
21
|
<center>
|
20
22
|
<table id="features">
|
@@ -45,6 +47,10 @@
|
|
45
47
|
</tr>
|
46
48
|
<% end %>
|
47
49
|
</tbody>
|
50
|
+
<%else%>
|
51
|
+
<tbody>
|
52
|
+
<tr><th colspan="10">Currently there are no features present!</th></tr>
|
53
|
+
</tbody>
|
48
54
|
<% end %>
|
49
55
|
</table>
|
50
56
|
</center>
|
@@ -7,26 +7,5 @@
|
|
7
7
|
|
8
8
|
<div class="feature-div">
|
9
9
|
<p style="font-weight:bold;font-size:23px">Add new Feature</p>
|
10
|
-
<%=
|
11
|
-
<div class ="field">
|
12
|
-
<label>Name : </label> <br/>
|
13
|
-
<%= f.text_field :name %>
|
14
|
-
<div class ="errors">
|
15
|
-
<% if @feature.errors.any? %>
|
16
|
-
<% @feature.errors.full_messages.each do |error| %>
|
17
|
-
<%= error %>
|
18
|
-
<% end %>
|
19
|
-
<% end %>
|
20
|
-
</div>
|
21
|
-
|
22
|
-
</div>
|
23
|
-
<div class ="field">
|
24
|
-
<label>Status : </label>
|
25
|
-
<%= f.check_box :status %><label>Enabled </label> <br/>
|
26
|
-
</div>
|
27
|
-
<div class ="field">
|
28
|
-
<%= f.submit "Submit" %>
|
29
|
-
</div>
|
30
|
-
<% end %>
|
31
|
-
|
10
|
+
<%= render :partial => "/feature_flags/form" , :locals => {:path => feature_flags_path,:method =>:post,:feature => @feature } %>
|
32
11
|
</div>
|
data/lib/feature_flags.rb
CHANGED
@@ -4,7 +4,11 @@ require "feature_flags/configuration"
|
|
4
4
|
require "feature_flags/manage_features"
|
5
5
|
require "feature_flags/engine"
|
6
6
|
require "active_support/dependencies"
|
7
|
+
require "feature_flags/feature_base"
|
8
|
+
require 'pstore'
|
9
|
+
require 'feature_flags/storage'
|
7
10
|
|
8
11
|
module FeatureFlags
|
9
12
|
# Your code goes here...\
|
13
|
+
FeatureFlags.update_pstore_value
|
10
14
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module FeatureFlags
|
2
|
+
module FeatureBase
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
after_save :update_hash
|
7
|
+
after_destroy :update_hash
|
8
|
+
end
|
9
|
+
|
10
|
+
@@features_hash = {}
|
11
|
+
|
12
|
+
|
13
|
+
#returns features hash
|
14
|
+
def self.features
|
15
|
+
##checking value in pstore if false then update to true and update features_hash
|
16
|
+
pstore_value = get_pstore_value
|
17
|
+
@@features_hash = {} unless (pstore_value.present? && !defined? Rails::Console)
|
18
|
+
|
19
|
+
if(@@features_hash.present? && pstore_value.present?)
|
20
|
+
@@features_hash
|
21
|
+
else
|
22
|
+
set_hash
|
23
|
+
Feature.new.update_pstore_hash
|
24
|
+
end
|
25
|
+
|
26
|
+
@@features_hash
|
27
|
+
end
|
28
|
+
|
29
|
+
###returns current value in pstore
|
30
|
+
def self.get_pstore_value
|
31
|
+
store = PStore.new('feature_flags')
|
32
|
+
store.transaction {store[:updated]}
|
33
|
+
end
|
34
|
+
|
35
|
+
#updates hash for features
|
36
|
+
def self.set_hash
|
37
|
+
@@features_hash = {}
|
38
|
+
Feature.all.map{|f| @@features_hash[f.name.to_s.intern] = f.status}
|
39
|
+
@@features_hash.freeze
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_hash
|
43
|
+
FeatureFlags::FeatureBase.set_hash
|
44
|
+
update_pstore_hash
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_pstore_hash
|
48
|
+
FeatureFlags.update_pstore_value(!defined? Rails::Console)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module FeatureFlags
|
2
|
-
def self.enabled?(
|
3
|
-
feature
|
2
|
+
def self.enabled?(feature)
|
3
|
+
feature.is_a?(Array) ? !check_features(feature) : get_feature(feature)
|
4
|
+
end
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
def self.enabled_any?(features = [])
|
7
|
+
check_features(features, true)
|
8
|
+
end
|
9
|
+
|
10
|
+
## checking dependant features
|
11
|
+
def self.check_features(features, check = false)
|
12
|
+
features.map{|feature| get_feature(feature)}.compact.include? check
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.create_and_enable(feature_name)
|
@@ -19,38 +19,53 @@ module FeatureFlags
|
|
19
19
|
|
20
20
|
def self.enable(feature_name)
|
21
21
|
feature = Feature.where(:name => feature_name).last
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
else
|
27
|
-
false
|
28
|
-
end
|
22
|
+
throw_error(feature_name) unless feature.present?
|
23
|
+
|
24
|
+
if feature.update_attributes(:status => true)
|
25
|
+
return true
|
29
26
|
else
|
30
|
-
|
27
|
+
flash[:error] = "#{feature_name} could not be updated"
|
28
|
+
return false
|
31
29
|
end
|
30
|
+
|
32
31
|
end
|
33
32
|
|
34
33
|
def self.set_disabled(feature_name)
|
35
34
|
feature = Feature.where(:name => feature_name).last
|
36
|
-
|
35
|
+
throw_error(feature_name) unless feature.present?
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
else
|
41
|
-
false
|
42
|
-
end
|
37
|
+
if feature.update_attributes(:status => false)
|
38
|
+
return true
|
43
39
|
else
|
44
|
-
|
40
|
+
flash[:error] = "#{feature_name} could not be updated"
|
41
|
+
return false
|
45
42
|
end
|
46
43
|
end
|
47
44
|
|
45
|
+
#disables all features in application
|
48
46
|
def self.disable_all
|
49
47
|
Feature.update_all(:status => false)
|
48
|
+
Feature.last.update_attributes(:status => false)
|
50
49
|
end
|
51
50
|
|
51
|
+
#enables all features in application
|
52
52
|
def self.enable_all
|
53
53
|
Feature.update_all(:status => true)
|
54
|
+
Feature.last.update_attributes(:status => true)
|
55
|
+
end
|
56
|
+
|
57
|
+
#fetch feature's status
|
58
|
+
def self.get_feature(feature_name)
|
59
|
+
all_features = FeatureFlags::FeatureBase.features
|
60
|
+
all_features.has_key?(feature_name) ? all_features[feature_name] : throw_error(feature_name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.throw_error(feature_name)
|
64
|
+
raise "#{feature_name} feature not found."
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.update_feature_hash
|
68
|
+
Feature.new.update_hash
|
54
69
|
end
|
55
70
|
|
56
71
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module FeatureFlags
|
2
|
+
|
3
|
+
#storing toggle value inside pstore if in case someone updates from rails console
|
4
|
+
def self.update_pstore_value(updated = true)
|
5
|
+
store = PStore.new('feature_flags')
|
6
|
+
store.transaction do
|
7
|
+
store[:updated] = updated
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
@@ -31,6 +31,8 @@ module FeatureFlags
|
|
31
31
|
|
32
32
|
def copy_feature_migration
|
33
33
|
template "feature_flag_migrate.rb", "db/migrate/#{MigrationNumber.next_migration_number}_create_features.rb"
|
34
|
+
|
35
|
+
##commented model file generation
|
34
36
|
template "feature_flag_model.rb", "app/models/feature.rb"
|
35
37
|
end
|
36
38
|
|
@@ -1,7 +1,13 @@
|
|
1
|
-
class Feature< ActiveRecord::Base
|
1
|
+
class Feature < ActiveRecord::Base
|
2
2
|
|
3
|
+
#### IMPORTANT start ####
|
4
|
+
### Dont remove this as this required for memoization of features...
|
5
|
+
include FeatureFlags::FeatureBase
|
6
|
+
#### IMPORTANT end ####
|
7
|
+
|
8
|
+
|
3
9
|
validates :name, presence: true
|
4
10
|
|
5
11
|
attr_accessible :name, :status
|
6
|
-
|
12
|
+
|
7
13
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feature_flags
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -56,6 +56,8 @@ files:
|
|
56
56
|
- README.md
|
57
57
|
- Rakefile
|
58
58
|
- app/controllers/feature_flags_controller.rb
|
59
|
+
- app/views/feature_flags/_form.html.erb
|
60
|
+
- app/views/feature_flags/_options.html.erb
|
59
61
|
- app/views/feature_flags/edit.html.erb
|
60
62
|
- app/views/feature_flags/index.html.erb
|
61
63
|
- app/views/feature_flags/new.html.erb
|
@@ -65,7 +67,9 @@ files:
|
|
65
67
|
- lib/feature_flags.rb
|
66
68
|
- lib/feature_flags/configuration.rb
|
67
69
|
- lib/feature_flags/engine.rb
|
70
|
+
- lib/feature_flags/feature_base.rb
|
68
71
|
- lib/feature_flags/manage_features.rb
|
72
|
+
- lib/feature_flags/storage.rb
|
69
73
|
- lib/feature_flags/version.rb
|
70
74
|
- lib/generators/feature_flags/install_generator.rb
|
71
75
|
- lib/generators/feature_flags/templates/feature_flag.rb
|
@@ -94,9 +98,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
98
|
version: '0'
|
95
99
|
requirements: []
|
96
100
|
rubyforge_project:
|
97
|
-
rubygems_version: 1.8.
|
101
|
+
rubygems_version: 1.8.23
|
98
102
|
signing_key:
|
99
103
|
specification_version: 3
|
100
104
|
summary: Manage (turn on/off) different features in your rails app.
|
101
105
|
test_files: []
|
102
|
-
has_rdoc:
|