fluidfeatures-rails 0.1.3 → 0.1.4
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 +1 -1
- data/lib/fluidfeatures/rails/version.rb +1 -1
- data/lib/fluidfeatures/rails.rb +93 -40
- data/test/testapp/spec/controllers/home_controller_spec.rb +14 -16
- metadata +2 -2
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](http://travis-ci.org/FluidFeatures/fluidfeatures-rails)
|
2
2
|
|
3
3
|
fluidfeatures-rails
|
4
4
|
===================
|
data/lib/fluidfeatures/rails.rb
CHANGED
@@ -1,26 +1,37 @@
|
|
1
1
|
|
2
|
-
require 'rails'
|
3
|
-
require 'net/http'
|
4
|
-
require 'persistent_http'
|
5
|
-
|
6
|
-
#
|
7
|
-
# Without these FluidFeatures credentials we cannot talk to
|
8
|
-
# the FluidFeatures service.
|
9
|
-
#
|
10
|
-
%w[FLUIDFEATURES_BASEURI FLUIDFEATURES_SECRET FLUIDFEATURES_APPID].each do |key|
|
11
|
-
unless ENV[key]
|
12
|
-
raise "Environment variable #{key} expected"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
2
|
module FluidFeatures
|
17
3
|
module Rails
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :enabled
|
7
|
+
end
|
18
8
|
|
19
9
|
#
|
20
10
|
# This is called once, when your Rails application fires up.
|
21
11
|
# It sets up the before and after request hooks
|
22
12
|
#
|
23
13
|
def self.initializer
|
14
|
+
|
15
|
+
#
|
16
|
+
# Without these FluidFeatures credentials we cannot talk to
|
17
|
+
# the FluidFeatures service.
|
18
|
+
#
|
19
|
+
%w[FLUIDFEATURES_BASEURI FLUIDFEATURES_SECRET FLUIDFEATURES_APPID].each do |key|
|
20
|
+
unless ENV[key]
|
21
|
+
$stderr.puts "!! fluidfeatures-rails requires ENV[\"#{key}\"] (fluidfeatures is disabled)"
|
22
|
+
return
|
23
|
+
end
|
24
|
+
end
|
25
|
+
unless defined? ::Rails
|
26
|
+
$stderr.puts "!! fluidfeatures-rails requires rails (fluidfeatures is disabled)"
|
27
|
+
return
|
28
|
+
end
|
29
|
+
$stderr.puts "=> fluidfeatures-rails initializing as app #{ENV["FLUIDFEATURES_APPID"]} with #{ENV["FLUIDFEATURES_BASEURI"]}"
|
30
|
+
|
31
|
+
|
32
|
+
require 'net/http'
|
33
|
+
require 'persistent_http'
|
34
|
+
|
24
35
|
::Rails::Application.initializer "fluidfeatures.initializer" do
|
25
36
|
ActiveSupport.on_load(:action_controller) do
|
26
37
|
|
@@ -38,11 +49,13 @@ module FluidFeatures
|
|
38
49
|
@@unknown_features = {}
|
39
50
|
@@last_fetch_duration = nil
|
40
51
|
|
41
|
-
ActionController::Base.append_before_filter :
|
42
|
-
ActionController::Base.append_after_filter
|
52
|
+
ActionController::Base.append_before_filter :fluidfeatures_request_before
|
53
|
+
ActionController::Base.append_after_filter :fluidfeatures_request_after
|
43
54
|
|
44
55
|
end
|
45
56
|
end
|
57
|
+
|
58
|
+
@enabled = true
|
46
59
|
end
|
47
60
|
|
48
61
|
#
|
@@ -156,30 +169,18 @@ module FluidFeatures
|
|
156
169
|
# back with the default_enabled status (see unknown_feature_hit)
|
157
170
|
# so that FluidFeatures can auto-populate the dashboard.
|
158
171
|
#
|
159
|
-
def self.
|
172
|
+
def self.log_request(user_id, payload)
|
160
173
|
begin
|
161
|
-
|
174
|
+
(payload[:stats] ||= {})[:ff_latency] = @@last_fetch_duration
|
175
|
+
if @@unknown_features.size
|
176
|
+
(payload[:features] ||= {})[:unknown] = @@unknown_features
|
177
|
+
@@unknown_features = {}
|
178
|
+
end
|
179
|
+
uri = URI(@@baseuri + "/app/#{@@app_id}/user/#{user_id}/features/hit")
|
162
180
|
request = Net::HTTP::Post.new uri.path
|
163
181
|
request["Content-Type"] = "application/json"
|
164
182
|
request["Accept"] = "application/json"
|
165
183
|
request['AUTHORIZATION'] = @@secret
|
166
|
-
payload = {
|
167
|
-
:stats => {
|
168
|
-
:fetch => {
|
169
|
-
:duration => @@last_fetch_duration
|
170
|
-
},
|
171
|
-
:request => {
|
172
|
-
:duration => request_duration
|
173
|
-
}
|
174
|
-
},
|
175
|
-
:features => {
|
176
|
-
:hit => features_hit
|
177
|
-
}
|
178
|
-
}
|
179
|
-
if @@unknown_features.size
|
180
|
-
payload[:features][:unknown] = @@unknown_features
|
181
|
-
@@unknown_features = {}
|
182
|
-
end
|
183
184
|
request.body = JSON.dump(payload)
|
184
185
|
response = @@http.request request
|
185
186
|
unless response.is_a?(Net::HTTPSuccess)
|
@@ -197,14 +198,45 @@ end
|
|
197
198
|
module ActionController
|
198
199
|
class Base
|
199
200
|
|
201
|
+
# allow fluidfeature to be called from templates
|
202
|
+
helper_method :fluidfeature
|
203
|
+
|
200
204
|
#
|
201
205
|
# Here is how we know what your user_id is for the user
|
202
206
|
# making the current request.
|
203
207
|
# This must be overriden within the user application.
|
204
208
|
# We recommend doing this in application_controller.rb
|
205
209
|
#
|
206
|
-
def fluidfeatures_set_user_id(user_id)
|
210
|
+
def fluidfeatures_set_user_id(user_id, options={})
|
211
|
+
|
212
|
+
if user_id and not options[:anonymous]
|
213
|
+
# We no longer an anoymous users. Let's delete the cookie
|
214
|
+
if cookies.has_key? :fluidfeatures_anonymous
|
215
|
+
cookies.delete(:fluidfeatures_anonymous)
|
216
|
+
end
|
217
|
+
else
|
218
|
+
# We're an anonymous user
|
219
|
+
|
220
|
+
# if we were not given a user_id for this anonymous user, then get
|
221
|
+
# it from an existing cookie or create a new one.
|
222
|
+
unless user_id
|
223
|
+
# Have we seen them before?
|
224
|
+
if cookies.has_key? :fluidfeatures_anonymous
|
225
|
+
user_id = cookies[:fluidfeatures_anonymous]
|
226
|
+
else
|
227
|
+
# Create new cookie. Use rand + micro-seconds of current time
|
228
|
+
user_id = "anon-" + Random.rand(9999999999).to_s + "-" + ((Time.now.to_f * 1000000).to_i % 1000000).to_s
|
229
|
+
end
|
230
|
+
end
|
231
|
+
# update the cookie, with whatever the user_id has been set to
|
232
|
+
cookies[:fluidfeatures_anonymous] = user_id
|
233
|
+
end
|
234
|
+
|
207
235
|
@ff_user_id = user_id
|
236
|
+
@ff_user_anonymous = !!options[:anonymous]
|
237
|
+
@ff_user_attributes = options[:attributes]
|
238
|
+
|
239
|
+
user_id
|
208
240
|
end
|
209
241
|
|
210
242
|
#
|
@@ -217,6 +249,9 @@ module ActionController
|
|
217
249
|
if defaults === true or defaults === false
|
218
250
|
defaults = { :enabled => defaults }
|
219
251
|
end
|
252
|
+
unless ::FluidFeatures::Rails.enabled
|
253
|
+
return defaults[:enabled] || false
|
254
|
+
end
|
220
255
|
global_defaults = fluidfeatures_defaults || {}
|
221
256
|
version_name = (defaults[:version] || global_defaults[:version]).to_s
|
222
257
|
if not @features
|
@@ -254,7 +289,7 @@ module ActionController
|
|
254
289
|
#
|
255
290
|
# Initialize the FluidFeatures state for this request.
|
256
291
|
#
|
257
|
-
def
|
292
|
+
def fluidfeatures_request_before
|
258
293
|
@ff_request_start_time = Time.now
|
259
294
|
@features = nil
|
260
295
|
end
|
@@ -273,10 +308,28 @@ module ActionController
|
|
273
308
|
# This helps the FluidFeatures database prepopulate the feature set
|
274
309
|
# without requiring the developer to do it manually.
|
275
310
|
#
|
276
|
-
def
|
311
|
+
def fluidfeatures_request_after
|
277
312
|
if @features
|
278
313
|
request_duration = Time.now - @ff_request_start_time
|
279
|
-
|
314
|
+
url = "#{request.protocol}#{request.host_with_port}#{request.fullpath}"
|
315
|
+
payload = {
|
316
|
+
:stats => {
|
317
|
+
:request => {
|
318
|
+
:duration => request_duration
|
319
|
+
}
|
320
|
+
},
|
321
|
+
:features => {
|
322
|
+
:hit => @features_hit
|
323
|
+
},
|
324
|
+
:url => url
|
325
|
+
}
|
326
|
+
if @ff_user_anonymous
|
327
|
+
(payload[:user] ||= {})[:anonymous] = true
|
328
|
+
end
|
329
|
+
if @ff_user_attributes
|
330
|
+
(payload[:user] ||= {})[:attributes] = @ff_user_attributes
|
331
|
+
end
|
332
|
+
FluidFeatures::Rails.log_request(@ff_user_id, payload)
|
280
333
|
end
|
281
334
|
end
|
282
335
|
|
@@ -284,7 +337,7 @@ module ActionController
|
|
284
337
|
# By default unknown features are disabled.
|
285
338
|
{
|
286
339
|
:enabled => false,
|
287
|
-
:version =>
|
340
|
+
:version => :default
|
288
341
|
}
|
289
342
|
end
|
290
343
|
|
@@ -38,33 +38,33 @@ describe HomeController do
|
|
38
38
|
|
39
39
|
# Check the call to features hit
|
40
40
|
features_hit_request = FakeWeb.last_request
|
41
|
-
JsonSpec.exclude_keys("duration")
|
41
|
+
JsonSpec.exclude_keys("duration", "ff_latency")
|
42
42
|
features_hit_request.body.should be_json_eql(%({
|
43
43
|
"features": {
|
44
44
|
"hit": {
|
45
45
|
"apples": {
|
46
|
-
"
|
46
|
+
"default": {}
|
47
47
|
}
|
48
48
|
},
|
49
49
|
"unknown": {
|
50
50
|
// features that we have not seen before
|
51
51
|
"apples": {
|
52
52
|
"versions": {
|
53
|
-
"
|
53
|
+
"default": {
|
54
54
|
"enabled": true
|
55
55
|
}
|
56
56
|
}
|
57
57
|
},
|
58
58
|
"lemons": {
|
59
59
|
"versions": {
|
60
|
-
"
|
60
|
+
"default": {
|
61
61
|
"enabled": false
|
62
62
|
}
|
63
63
|
}
|
64
64
|
},
|
65
65
|
"oranges": {
|
66
66
|
"versions": {
|
67
|
-
"
|
67
|
+
"default": {
|
68
68
|
"enabled": false
|
69
69
|
}
|
70
70
|
}
|
@@ -72,13 +72,12 @@ describe HomeController do
|
|
72
72
|
}
|
73
73
|
},
|
74
74
|
"stats": {
|
75
|
-
"
|
76
|
-
// duration ignored
|
77
|
-
},
|
75
|
+
"ff_latency": 1,
|
78
76
|
"request": {
|
79
77
|
// duration ignored
|
80
78
|
}
|
81
|
-
}
|
79
|
+
},
|
80
|
+
"url": "http://test.host/?user_id=1"
|
82
81
|
}))
|
83
82
|
end
|
84
83
|
|
@@ -89,15 +88,15 @@ describe HomeController do
|
|
89
88
|
|
90
89
|
# Check the call to features hit
|
91
90
|
features_hit_request = FakeWeb.last_request
|
92
|
-
JsonSpec.exclude_keys("duration")
|
91
|
+
JsonSpec.exclude_keys("duration", "ff_latency")
|
93
92
|
features_hit_request.body.should be_json_eql(%({
|
94
93
|
"features": {
|
95
94
|
"hit": {
|
96
95
|
"oranges": {
|
97
|
-
"
|
96
|
+
"default": {}
|
98
97
|
},
|
99
98
|
"lemons": {
|
100
|
-
"
|
99
|
+
"default": {}
|
101
100
|
}
|
102
101
|
},
|
103
102
|
"unknown": {
|
@@ -105,13 +104,12 @@ describe HomeController do
|
|
105
104
|
}
|
106
105
|
},
|
107
106
|
"stats": {
|
108
|
-
"
|
109
|
-
// duration ignored
|
110
|
-
},
|
107
|
+
"ff_latency": 1,
|
111
108
|
"request": {
|
112
109
|
// duration ignored
|
113
110
|
}
|
114
|
-
}
|
111
|
+
},
|
112
|
+
"url": "http://test.host/?user_id=2"
|
115
113
|
}))
|
116
114
|
end
|
117
115
|
|
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.1.
|
4
|
+
version: 0.1.4
|
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-09-
|
12
|
+
date: 2012-09-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: persistent_http
|