feature_flags 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|