fluidfeatures-rails 0.1.4 → 0.2.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/lib/fluidfeatures/rails/app/controllers/fluidfeatures_controller.rb +20 -0
- data/lib/fluidfeatures/rails/config/routes.rb +8 -0
- data/lib/fluidfeatures/rails/version.rb +1 -1
- data/lib/fluidfeatures/rails.rb +64 -47
- data/test/testapp/app/controllers/application_controller.rb +9 -10
- data/test/testapp/spec/controllers/home_controller_spec.rb +18 -4
- metadata +4 -2
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
class FluidFeatureAjaxController < ApplicationController
|
3
|
+
|
4
|
+
def index
|
5
|
+
render :json => {
|
6
|
+
:enabled => fluidfeature(params[:feature_name])
|
7
|
+
}, :status => 200
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# This is a controller you can use to sends stats from your browser
|
13
|
+
#
|
14
|
+
|
15
|
+
class FluidGoalAjaxController < ApplicationController
|
16
|
+
def index
|
17
|
+
fluidgoal(params[:goal_name], { :version => params[:goal_version] })
|
18
|
+
render :json => {}, :status => 200
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
|
2
|
+
require 'fluidfeatures/rails/app/controllers/fluidfeatures_controller'
|
3
|
+
|
4
|
+
Rails.application.routes.draw do
|
5
|
+
match "/fluidfeature/:feature_name" => "fluid_feature_ajax#index"
|
6
|
+
match "/fluidgoal/:goal_name" => "fluid_goal_ajax#index"
|
7
|
+
match "/fluidgoal/:goal_name/:goal_version" => "fluid_goal_ajax#index"
|
8
|
+
end
|
data/lib/fluidfeatures/rails.rb
CHANGED
@@ -207,9 +207,13 @@ module ActionController
|
|
207
207
|
# This must be overriden within the user application.
|
208
208
|
# We recommend doing this in application_controller.rb
|
209
209
|
#
|
210
|
-
def
|
210
|
+
def fluidfeatures_initialize_user
|
211
211
|
|
212
|
-
|
212
|
+
# TODO: Do not always get verbose user details.
|
213
|
+
# Get for new users and then less frequently.
|
214
|
+
user = fluidfeature_current_user(verbose=true)
|
215
|
+
|
216
|
+
if user[:id] and not user[:anonymous]
|
213
217
|
# We no longer an anoymous users. Let's delete the cookie
|
214
218
|
if cookies.has_key? :fluidfeatures_anonymous
|
215
219
|
cookies.delete(:fluidfeatures_anonymous)
|
@@ -217,28 +221,31 @@ module ActionController
|
|
217
221
|
else
|
218
222
|
# We're an anonymous user
|
219
223
|
|
220
|
-
# if we were not given a
|
224
|
+
# if we were not given a user[:id] for this anonymous user, then get
|
221
225
|
# it from an existing cookie or create a new one.
|
222
|
-
unless
|
226
|
+
unless user[:id]
|
223
227
|
# Have we seen them before?
|
224
228
|
if cookies.has_key? :fluidfeatures_anonymous
|
225
|
-
|
229
|
+
user[:id] = cookies[:fluidfeatures_anonymous]
|
226
230
|
else
|
227
231
|
# Create new cookie. Use rand + micro-seconds of current time
|
228
|
-
|
232
|
+
user[:id] = "anon-" + Random.rand(9999999999).to_s + "-" + ((Time.now.to_f * 1000000).to_i % 1000000).to_s
|
229
233
|
end
|
230
234
|
end
|
231
|
-
# update the cookie, with whatever the
|
232
|
-
cookies[:fluidfeatures_anonymous] =
|
235
|
+
# update the cookie, with whatever the user[:id] has been set to
|
236
|
+
cookies[:fluidfeatures_anonymous] = user[:id]
|
233
237
|
end
|
238
|
+
user[:anonymous] = !!user[:anonymous]
|
239
|
+
@ff_user = user
|
240
|
+
end
|
234
241
|
|
235
|
-
|
236
|
-
@
|
237
|
-
|
238
|
-
|
239
|
-
|
242
|
+
def fluidfeatures_user
|
243
|
+
unless @ff_user
|
244
|
+
fluidfeatures_initialize_user
|
245
|
+
end
|
246
|
+
@ff_user
|
240
247
|
end
|
241
|
-
|
248
|
+
|
242
249
|
#
|
243
250
|
# This is called by the developer's code to determine if the
|
244
251
|
# feature, specified by "feature_name" is enabled for the
|
@@ -254,15 +261,15 @@ module ActionController
|
|
254
261
|
end
|
255
262
|
global_defaults = fluidfeatures_defaults || {}
|
256
263
|
version_name = (defaults[:version] || global_defaults[:version]).to_s
|
257
|
-
if not @
|
264
|
+
if not @ff_features
|
258
265
|
fluidfeatures_retrieve_user_features
|
259
266
|
end
|
260
|
-
if @
|
261
|
-
if @
|
262
|
-
enabled = @
|
263
|
-
elsif @
|
264
|
-
if @
|
265
|
-
enabled = @
|
267
|
+
if @ff_features.has_key? feature_name
|
268
|
+
if @ff_features[feature_name].is_a? FalseClass or @ff_features[feature_name].is_a? TrueClass
|
269
|
+
enabled = @ff_features[feature_name]
|
270
|
+
elsif @ff_features[feature_name].is_a? Hash
|
271
|
+
if @ff_features[feature_name].has_key? version_name
|
272
|
+
enabled = @ff_features[feature_name][version_name]
|
266
273
|
end
|
267
274
|
end
|
268
275
|
end
|
@@ -279,26 +286,34 @@ module ActionController
|
|
279
286
|
FluidFeatures::Rails.unknown_feature_hit(feature_name, version_name, options)
|
280
287
|
end
|
281
288
|
if enabled
|
282
|
-
@
|
283
|
-
@
|
284
|
-
@features_hit[feature_name][version_name.to_s] = {}
|
289
|
+
@ff_features_hit[feature_name] ||= {}
|
290
|
+
@ff_features_hit[feature_name][version_name.to_s] = {}
|
285
291
|
end
|
286
292
|
enabled
|
287
293
|
end
|
288
294
|
|
295
|
+
def fluidgoal(goal_name, defaults={})
|
296
|
+
global_defaults = fluidfeatures_defaults || {}
|
297
|
+
version_name = (defaults[:version] || global_defaults[:version]).to_s
|
298
|
+
@ff_goals_hit[goal_name] ||= {}
|
299
|
+
@ff_goals_hit[goal_name][version_name.to_s] = {}
|
300
|
+
end
|
301
|
+
|
289
302
|
#
|
290
303
|
# Initialize the FluidFeatures state for this request.
|
291
304
|
#
|
292
305
|
def fluidfeatures_request_before
|
293
306
|
@ff_request_start_time = Time.now
|
294
|
-
@
|
307
|
+
@ff_features = nil
|
308
|
+
@ff_features_hit = {}
|
309
|
+
@ff_goals_hit = {}
|
295
310
|
end
|
296
311
|
|
297
312
|
#
|
298
313
|
# Returns the features enabled for this request's user.
|
299
314
|
#
|
300
315
|
def fluidfeatures_retrieve_user_features
|
301
|
-
@
|
316
|
+
@ff_features = FluidFeatures::Rails.get_user_features(fluidfeatures_user[:id])
|
302
317
|
end
|
303
318
|
|
304
319
|
#
|
@@ -309,28 +324,30 @@ module ActionController
|
|
309
324
|
# without requiring the developer to do it manually.
|
310
325
|
#
|
311
326
|
def fluidfeatures_request_after
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
:
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
:
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
327
|
+
request_duration = Time.now - @ff_request_start_time
|
328
|
+
url = "#{request.protocol}#{request.host_with_port}#{request.fullpath}"
|
329
|
+
payload = {
|
330
|
+
:user => {
|
331
|
+
:id => fluidfeatures_user[:id]
|
332
|
+
},
|
333
|
+
:stats => {
|
334
|
+
:request => {
|
335
|
+
:duration => request_duration
|
336
|
+
}
|
337
|
+
},
|
338
|
+
:hits => {
|
339
|
+
:feature => @ff_features_hit,
|
340
|
+
:goal => @ff_goals_hit
|
341
|
+
},
|
342
|
+
:url => url
|
343
|
+
}
|
344
|
+
if fluidfeatures_user[:anonymous]
|
345
|
+
(payload[:user] ||= {})[:anonymous] = true
|
346
|
+
end
|
347
|
+
if fluidfeatures_user[:attributes]
|
348
|
+
(payload[:user] ||= {})[:attributes] = fluidfeatures_user[:attributes]
|
333
349
|
end
|
350
|
+
FluidFeatures::Rails.log_request(fluidfeatures_user[:id], payload)
|
334
351
|
end
|
335
352
|
|
336
353
|
def fluidfeatures_defaults
|
@@ -1,17 +1,16 @@
|
|
1
1
|
class ApplicationController < ActionController::Base
|
2
|
-
protect_from_forgery
|
3
|
-
|
4
|
-
before_filter :authenticate_user
|
5
2
|
|
6
3
|
# simple authentication. user passes their id
|
7
4
|
def authenticate_user
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
params[:user_id]
|
6
|
+
end
|
7
|
+
|
8
|
+
def current_user_id
|
9
|
+
@current_user_id ||= authenticate_user
|
10
|
+
end
|
11
|
+
|
12
|
+
def fluidfeature_current_user(verbose=false)
|
13
|
+
{ :id => current_user_id }
|
15
14
|
end
|
16
15
|
|
17
16
|
end
|
@@ -40,12 +40,19 @@ describe HomeController do
|
|
40
40
|
features_hit_request = FakeWeb.last_request
|
41
41
|
JsonSpec.exclude_keys("duration", "ff_latency")
|
42
42
|
features_hit_request.body.should be_json_eql(%({
|
43
|
-
"
|
44
|
-
"
|
43
|
+
"user": {
|
44
|
+
"id": "1"
|
45
|
+
},
|
46
|
+
"hits": {
|
47
|
+
"feature": {
|
45
48
|
"apples": {
|
46
49
|
"default": {}
|
47
50
|
}
|
48
51
|
},
|
52
|
+
"goal": {
|
53
|
+
}
|
54
|
+
},
|
55
|
+
"features": {
|
49
56
|
"unknown": {
|
50
57
|
// features that we have not seen before
|
51
58
|
"apples": {
|
@@ -90,8 +97,11 @@ describe HomeController do
|
|
90
97
|
features_hit_request = FakeWeb.last_request
|
91
98
|
JsonSpec.exclude_keys("duration", "ff_latency")
|
92
99
|
features_hit_request.body.should be_json_eql(%({
|
93
|
-
"
|
94
|
-
"
|
100
|
+
"user": {
|
101
|
+
"id": "2"
|
102
|
+
},
|
103
|
+
"hits": {
|
104
|
+
"feature": {
|
95
105
|
"oranges": {
|
96
106
|
"default": {}
|
97
107
|
},
|
@@ -99,6 +109,10 @@ describe HomeController do
|
|
99
109
|
"default": {}
|
100
110
|
}
|
101
111
|
},
|
112
|
+
"goal": {
|
113
|
+
}
|
114
|
+
},
|
115
|
+
"features": {
|
102
116
|
"unknown": {
|
103
117
|
// no unknown features
|
104
118
|
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluidfeatures-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.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: 2012-
|
12
|
+
date: 2012-10-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: persistent_http
|
@@ -41,6 +41,8 @@ files:
|
|
41
41
|
- Rakefile
|
42
42
|
- fluidfeatures-rails.gemspec
|
43
43
|
- lib/fluidfeatures/rails.rb
|
44
|
+
- lib/fluidfeatures/rails/app/controllers/fluidfeatures_controller.rb
|
45
|
+
- lib/fluidfeatures/rails/config/routes.rb
|
44
46
|
- lib/fluidfeatures/rails/version.rb
|
45
47
|
- test/testapp/.gitignore
|
46
48
|
- test/testapp/Gemfile
|