fluidfeatures-rails 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://secure.travis-ci.org/BigFastSite/fluidfeatures-rails.png)](http://travis-ci.org/BigFastSite/fluidfeatures-rails)
1
+ [![Build Status](https://secure.travis-ci.org/FluidFeatures/fluidfeatures-rails.png)](http://travis-ci.org/FluidFeatures/fluidfeatures-rails)
2
2
 
3
3
  fluidfeatures-rails
4
4
  ===================
@@ -1,5 +1,5 @@
1
1
  module FluidFeatures
2
2
  module Rails
3
- VERSION = '0.1.3'
3
+ VERSION = '0.1.4'
4
4
  end
5
5
  end
@@ -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 :fluidfeatures_request_init
42
- ActionController::Base.append_after_filter :fluidfeatures_store_features_hit
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.log_features_hit(user_id, features_hit, request_duration)
172
+ def self.log_request(user_id, payload)
160
173
  begin
161
- uri = URI(@@baseuri + "/app/" + @@app_id.to_s + "/user/" + user_id.to_s + "/features/hit")
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 fluidfeatures_request_init
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 fluidfeatures_store_features_hit
311
+ def fluidfeatures_request_after
277
312
  if @features
278
313
  request_duration = Time.now - @ff_request_start_time
279
- FluidFeatures::Rails.log_features_hit(@ff_user_id, @features_hit, request_duration)
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 => 1
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
- "1": {}
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
- "1": {
53
+ "default": {
54
54
  "enabled": true
55
55
  }
56
56
  }
57
57
  },
58
58
  "lemons": {
59
59
  "versions": {
60
- "1": {
60
+ "default": {
61
61
  "enabled": false
62
62
  }
63
63
  }
64
64
  },
65
65
  "oranges": {
66
66
  "versions": {
67
- "1": {
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
- "fetch": {
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
- "1": {}
96
+ "default": {}
98
97
  },
99
98
  "lemons": {
100
- "1": {}
99
+ "default": {}
101
100
  }
102
101
  },
103
102
  "unknown": {
@@ -105,13 +104,12 @@ describe HomeController do
105
104
  }
106
105
  },
107
106
  "stats": {
108
- "fetch": {
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.3
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-01 00:00:00.000000000 Z
12
+ date: 2012-09-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: persistent_http