detour 0.0.7 → 0.0.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ca146964bc97965e5f1b493fb87c8c4fcd2b149
4
- data.tar.gz: da57f56e5998a03bc6559958a9dcc54f2bf62629
3
+ metadata.gz: 8684efda0b28c3dbd1dd637adced4476063e1b69
4
+ data.tar.gz: 7b8de882f70365420e74d75734583ac336f58762
5
5
  SHA512:
6
- metadata.gz: 4cdaf7bcfec46bdadbbc147f6baaddabf373fe610172afb531805f82250c3b292581281ba5a11aeeaac98dd87fd77ceb4e980d4165a7e0ca0a07fa2c1a8245e8
7
- data.tar.gz: d2535f168cadb5ff31bcd23055d96cac22971d8521a97903407563de976b741faada4ade8cb1ed826edb71ef8e94cac4439c38161787bec14de9be9ef13541b2
6
+ metadata.gz: 070f25d30517f8f1dbd062087e90db55f15b1a51a7eb456211a57123f71314ec33d93417d06ac5921ec2815fb784c8f666b2765a7c8eb290e8163188ce135849
7
+ data.tar.gz: 0080ba77c52c9de244cdc68676519ff81148ee4e190e60f5c9d9c54e903cfd343c1e5f6bd0861d239c66073e085977e658d57bc2fd01dc54525f2edec78b2391
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Detour
2
2
 
3
- Rollouts for `ActiveRecord` models. It is a spiritual fork of [ArRollout](https://github.com/markpundsack/ar_rollout).
3
+ Rollouts for `ActiveRecord` models. It is a spiritual fork of
4
+ [ArRollout](https://github.com/markpundsack/ar_rollout).
4
5
 
5
6
  | development status | master status | Code Climate |
6
7
  | ------------------ | ------------- | ------------ |
@@ -17,6 +18,7 @@ Rollouts for `ActiveRecord` models. It is a spiritual fork of [ArRollout](https:
17
18
  - [Installation](#installation)
18
19
  - [Usage](#usage)
19
20
  - [Configuration](#configuration)
21
+ - [Restricting the admin interface](#restricting-the-admin-interface)
20
22
  - [Marking a model as flaggable](#marking-a-model-as-flaggable)
21
23
  - [Determining if a record is flagged into a feature](#determining-if-a-record-is-flagged-into-a-feature)
22
24
  - [Defining programmatic groups](#defining-programmatic-groups)
@@ -44,7 +46,8 @@ Run the Detour migrations:
44
46
 
45
47
  `Detour` works by determining whether or not a specific record
46
48
  should have features accessible to it based on individual flags, flags for a
47
- percentage of records, or flags for a programmable group of records.
49
+ percentage of records, flags for a database-backed group of records, or flags
50
+ for a code-defined group of records.
48
51
 
49
52
  ### Configuration
50
53
 
@@ -61,11 +64,6 @@ Detour.configure do |config|
61
64
  # checking for flags in your code. Provide it an
62
65
  # array of glob strings:
63
66
  config.feature_search_dirs = %w[app/**/*.{rb,erb}]
64
-
65
- # Provide a default class to manage rollouts for, if
66
- # desired. This means you can omit the class name from
67
- # rake tasks:
68
- config.default_flaggable_class_name = "User"
69
67
  end
70
68
  ```
71
69
 
@@ -77,6 +75,37 @@ Rails.application.routes.draw do
77
75
  end
78
76
  ```
79
77
 
78
+ ### Restricting the admin interface
79
+
80
+ If you'd like your Detour admin interface only accessible to admins, for example,
81
+ you can add a `before_filter` to `Detour::ApplicationController` in the Detour
82
+ initializer:
83
+
84
+ ```ruby
85
+ # config/initializers/detour.rb
86
+
87
+ Detour::ApplicationController.class_eval do
88
+ include CurrentUser
89
+
90
+ before_filter :admin_required!
91
+
92
+ private
93
+
94
+ def admin_required!
95
+ if current_user && current_user.admin?
96
+ true
97
+ else
98
+ # redirect somewhere for non-admins
99
+ end
100
+ end
101
+ end
102
+ ```
103
+
104
+ Since `Detour::ApplicationController` isn't a subclass of my `ApplicationController`,
105
+ I've included a `CurrentUser` module that I built in this app that adds a
106
+ `current_user` method to any controller that it's included in. Now, only admins
107
+ will have access to the Detour admin interface.
108
+
80
109
  ### Marking a model as flaggable
81
110
 
82
111
  In addition to listing classes that are flaggable in your initializer, add
@@ -4,9 +4,10 @@ class Detour::FlaggableFlagsController < Detour::ApplicationController
4
4
  include Detour::FlaggableFlagsHelper
5
5
 
6
6
  before_filter :ensure_flaggable_type_exists
7
+ before_filter :ensure_flag_type_exists
7
8
 
8
9
  def index
9
- @feature = Detour::Feature.find_by_name!(params[:feature_name])
10
+ @feature = Detour::Feature.where(name: params[:feature_name]).first_or_create!
10
11
  end
11
12
 
12
13
  def update
@@ -14,9 +15,17 @@ class Detour::FlaggableFlagsController < Detour::ApplicationController
14
15
 
15
16
  if @feature.update_attributes(params[:feature])
16
17
  flash[:notice] = "Your #{flag_noun.pluralize} have been updated"
17
- redirect_to send("#{flag_type}_flags_path", feature_name: params[:feature_name], flaggable_type: params[:flaggable_type])
18
+ redirect_to flaggable_flags_path flag_type: params[:flag_type], feature_name: params[:feature_name], flaggable_type: params[:flaggable_type]
18
19
  else
19
20
  render :index
20
21
  end
21
22
  end
23
+
24
+ private
25
+
26
+ def ensure_flag_type_exists
27
+ unless %w[flag-ins opt-outs].include? params[:flag_type]
28
+ raise ActionController::RoutingError.new("Not Found")
29
+ end
30
+ end
22
31
  end
@@ -12,7 +12,7 @@ module Detour::FlaggableFlagsHelper
12
12
  end
13
13
 
14
14
  def flag_type
15
- request.path.split("/")[2].underscore.singularize
15
+ params[:flag_type].underscore
16
16
  end
17
17
 
18
18
  def flag_verb
@@ -8,12 +8,12 @@ class Detour::Feature < ActiveRecord::Base
8
8
  serialize :flag_in_counts, JSON
9
9
  serialize :opt_out_counts, JSON
10
10
 
11
- has_many :flag_in_flags
12
- has_many :defined_group_flags
13
- has_many :database_group_flags
14
- has_many :percentage_flags
15
- has_many :opt_out_flags
16
- has_many :flags, dependent: :destroy
11
+ has_many :flag_in_flags, dependent: :destroy
12
+ has_many :defined_group_flags, dependent: :destroy
13
+ has_many :database_group_flags, dependent: :destroy
14
+ has_many :percentage_flags, dependent: :destroy
15
+ has_many :opt_out_flags, dependent: :destroy
16
+ has_many :flags, dependent: :destroy
17
17
 
18
18
  validates_presence_of :name
19
19
  validates_uniqueness_of :name
@@ -33,13 +33,13 @@
33
33
  <% end %>
34
34
 
35
35
  <td class="flag-in-count">
36
- <%= link_to flag_in_flags_path(feature.name, params[:flaggable_type]) do %>
36
+ <%= link_to flaggable_flags_path(flag_type: "flag-ins", feature_name: feature.name, flaggable_type: params[:flaggable_type]) do %>
37
37
  <%= feature.flag_in_count_for(params[:flaggable_type]) %>
38
38
  <% end %>
39
39
  </td>
40
40
 
41
41
  <td class="opt-out-count">
42
- <%= link_to opt_out_flags_path(feature.name, params[:flaggable_type]) do %>
42
+ <%= link_to flaggable_flags_path(flag_type: "opt-outs", feature_name: feature.name, flaggable_type: params[:flaggable_type]) do %>
43
43
  <%= feature.opt_out_count_for(params[:flaggable_type]) %>
44
44
  <% end %>
45
45
  </td>
data/config/routes.rb CHANGED
@@ -5,12 +5,10 @@ Detour::Engine.routes.draw do
5
5
  resources :features, only: [:create, :destroy]
6
6
  resources :groups, only: [:index, :show, :create, :update, :destroy]
7
7
 
8
- %w[flag-ins opt-outs].each do |flag_type|
9
- scope "/#{flag_type}/:feature_name" do
10
- get ":flaggable_type" => "flaggable_flags#index", as: "#{flag_type.underscore.singularize}_flags"
11
- put ":flaggable_type" => "flaggable_flags#update"
12
- delete ":flaggable_type/:id" => "flaggable_flags#destroy", as: "#{flag_type.underscore.singularize}_flag"
13
- end
8
+ scope "/:flag_type/:feature_name" do
9
+ get ":flaggable_type" => "flaggable_flags#index", as: "flaggable_flags"
10
+ put ":flaggable_type" => "flaggable_flags#update"
11
+ delete ":flaggable_type/:id" => "flaggable_flags#destroy", as: "flaggable_flag"
14
12
  end
15
13
 
16
14
  root to: "application#index"
@@ -1,7 +1,6 @@
1
1
  class Detour::Configuration
2
2
  attr_reader :defined_groups
3
3
  attr_reader :feature_search_regex
4
- attr_accessor :default_flaggable_class_name
5
4
  attr_accessor :flaggable_types
6
5
  attr_accessor :feature_search_dirs
7
6
 
@@ -1,3 +1,3 @@
1
1
  module Detour
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -6,57 +6,96 @@ describe Detour::FlaggableFlagsController do
6
6
  describe "GET #index" do
7
7
  let(:flag) { create :flag_in_flag }
8
8
 
9
- before do
10
- get :index, feature_name: flag.feature.name, flaggable_type: "users"
9
+ context "when the flag type is invalid" do
10
+ def do_get
11
+ get :index, flag_type: "foo", feature_name: flag.feature.name, flaggable_type: "users"
12
+ end
13
+
14
+ it "returns a 404" do
15
+ expect { do_get }.to raise_error ActionController::RoutingError
16
+ end
11
17
  end
12
18
 
13
- it "assigns the feature" do
14
- assigns(:feature).should eq flag.feature
19
+ context "when the feature does not exist" do
20
+ before do
21
+ get :index, flag_type: "flag-ins", feature_name: "foo", flaggable_type: "users"
22
+ end
23
+
24
+ it "persists the feature" do
25
+ Detour::Feature.where(name: "foo").should_not be_nil
26
+ end
27
+
28
+ it "is a 200" do
29
+ response.status.should eq 200
30
+ end
15
31
  end
16
32
 
17
- it "renders the index template" do
18
- response.should render_template :index
33
+ context "when the flag type is valid" do
34
+ before do
35
+ get :index, flag_type: "flag-ins", feature_name: flag.feature.name, flaggable_type: "users"
36
+ end
37
+
38
+ it "assigns the feature" do
39
+ assigns(:feature).should eq flag.feature
40
+ end
41
+
42
+ it "renders the index template" do
43
+ response.should render_template :index
44
+ end
19
45
  end
20
46
  end
21
47
 
22
48
  describe "PUT #update" do
23
49
  let(:flag) { create :flag_in_flag }
24
50
 
25
- before do
26
- put :update, feature_name: flag.feature.name, flaggable_type: "users", feature: flag_params
51
+ context "when the flag type is invalid" do
52
+ def do_put
53
+ put :update, flag_type: "foo", feature_name: flag.feature.name, flaggable_type: "users", feature: {}
54
+ end
55
+
56
+ it "returns a 404" do
57
+ expect { do_put }.to raise_error ActionController::RoutingError
58
+ end
27
59
  end
28
60
 
29
- context "when successful" do
30
- let(:user) { create :user }
31
61
 
32
- let(:flag_params) do
33
- {
34
- users_flag_ins_attributes: {
35
- "1" => { flaggable_type: "User", flaggable_key: user.id, _destroy: 0 }
36
- }
37
- }
62
+ context "when the flag type is valid" do
63
+ before do
64
+ put :update, flag_type: "flag-ins", feature_name: flag.feature.name, flaggable_type: "users", feature: flag_params
38
65
  end
39
66
 
40
- it "sets a flash message" do
41
- flash[:notice].should eq "Your flag-ins have been updated"
42
- end
67
+ context "when successful" do
68
+ let(:user) { create :user }
43
69
 
44
- it "redirect to the group" do
45
- response.should redirect_to flag_in_flags_path(feature_name: flag.feature.name, flaggable_type: "users")
70
+ let(:flag_params) do
71
+ {
72
+ users_flag_ins_attributes: {
73
+ "1" => { flaggable_type: "User", flaggable_key: user.id, _destroy: 0 }
74
+ }
75
+ }
76
+ end
77
+
78
+ it "sets a flash message" do
79
+ flash[:notice].should eq "Your flag-ins have been updated"
80
+ end
81
+
82
+ it "redirect to the group" do
83
+ response.should redirect_to flaggable_flags_path(flag_type: "flag-ins", feature_name: flag.feature.name, flaggable_type: "users")
84
+ end
46
85
  end
47
- end
48
86
 
49
- context "when unsuccessful" do
50
- let(:flag_params) do
51
- {
52
- users_flag_ins_attributes: {
53
- "1" => { flaggable_type: "User", flaggable_key: nil, _destroy: 0 }
87
+ context "when unsuccessful" do
88
+ let(:flag_params) do
89
+ {
90
+ users_flag_ins_attributes: {
91
+ "1" => { flaggable_type: "User", flaggable_key: nil, _destroy: 0 }
92
+ }
54
93
  }
55
- }
56
- end
94
+ end
57
95
 
58
- it "renders the show template" do
59
- response.should render_template :index
96
+ it "renders the show template" do
97
+ response.should render_template :index
98
+ end
60
99
  end
61
100
  end
62
101
  end
@@ -2,11 +2,11 @@ require "spec_helper"
2
2
  require "fakefs/spec_helpers"
3
3
 
4
4
  describe Detour::Feature do
5
- it { should have_many(:flag_in_flags) }
6
- it { should have_many(:database_group_flags) }
7
- it { should have_many(:defined_group_flags) }
8
- it { should have_many(:percentage_flags) }
9
- it { should have_many(:opt_out_flags) }
5
+ it { should have_many(:flag_in_flags).dependent(:destroy) }
6
+ it { should have_many(:database_group_flags).dependent(:destroy) }
7
+ it { should have_many(:defined_group_flags).dependent(:destroy) }
8
+ it { should have_many(:percentage_flags).dependent(:destroy) }
9
+ it { should have_many(:opt_out_flags).dependent(:destroy) }
10
10
  it { should have_many(:flags).dependent(:destroy) }
11
11
  it { should validate_presence_of :name }
12
12
  it { should validate_uniqueness_of :name }
@@ -16,6 +16,7 @@ describe Detour::Feature do
16
16
  it { should allow_value("foo_bar").for(:name) }
17
17
  it { should allow_value("foo-bar").for(:name) }
18
18
  it { should_not allow_value("foo-bar.").for(:name) }
19
+ it { should_not allow_value("foo bar").for(:name) }
19
20
 
20
21
  describe "name format validation" do
21
22
  let(:feature) { build :feature, name: "foo bar." }
data/spec/spec_helper.rb CHANGED
@@ -57,7 +57,6 @@ RSpec.configure do |config|
57
57
  end
58
58
 
59
59
  config.after :each do
60
- Detour.config.default_flaggable_class_name = nil
61
60
  Detour.config.feature_search_dirs = []
62
61
  Detour.config.instance_variable_set "@defined_groups", {}
63
62
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: detour
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Clem
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-08 00:00:00.000000000 Z
11
+ date: 2014-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails