impressionist2 1.5.1

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.
Files changed (146) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +26 -0
  5. data/CHANGELOG.rdoc +82 -0
  6. data/Gemfile +26 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.md +250 -0
  9. data/Rakefile +34 -0
  10. data/app/controllers/impressionist_controller.rb +146 -0
  11. data/app/models/impression.rb +2 -0
  12. data/app/models/impressionist/bots.rb +1468 -0
  13. data/app/models/impressionist/impressionable.rb +62 -0
  14. data/gemfiles/rails32.gemfile +30 -0
  15. data/gemfiles/rails40.gemfile +30 -0
  16. data/gemfiles/rails50.gemfile +30 -0
  17. data/impressionist2.gemspec +23 -0
  18. data/lib/generators/active_record/impressionist_generator.rb +22 -0
  19. data/lib/generators/active_record/templates/create_impressions_table.rb +32 -0
  20. data/lib/generators/impressionist_generator.rb +13 -0
  21. data/lib/generators/mongo_mapper/impressionist_generator.rb +8 -0
  22. data/lib/generators/mongoid/impressionist_generator.rb +8 -0
  23. data/lib/generators/templates/impression.rb +8 -0
  24. data/lib/impressionist/bots.rb +21 -0
  25. data/lib/impressionist/controllers/mongoid/impressionist_controller.rb +10 -0
  26. data/lib/impressionist/counter_cache.rb +73 -0
  27. data/lib/impressionist/engine.rb +30 -0
  28. data/lib/impressionist/is_impressionable.rb +23 -0
  29. data/lib/impressionist/load.rb +11 -0
  30. data/lib/impressionist/models/active_record/impression.rb +14 -0
  31. data/lib/impressionist/models/active_record/impressionist/impressionable.rb +12 -0
  32. data/lib/impressionist/models/mongo_mapper/impression.rb +18 -0
  33. data/lib/impressionist/models/mongo_mapper/impressionist/impressionable.rb +21 -0
  34. data/lib/impressionist/models/mongoid/impression.rb +25 -0
  35. data/lib/impressionist/models/mongoid/impressionist/impressionable.rb +28 -0
  36. data/lib/impressionist/rails_toggle.rb +26 -0
  37. data/lib/impressionist/setup_association.rb +49 -0
  38. data/lib/impressionist/update_counters.rb +69 -0
  39. data/lib/impressionist/version.rb +3 -0
  40. data/lib/impressionist.rb +12 -0
  41. data/logo.png +0 -0
  42. data/tests/README +11 -0
  43. data/tests/spec/minitest_helper.rb +4 -0
  44. data/tests/spec/rails_toggle_spec.rb +38 -0
  45. data/tests/spec/setup_association_spec.rb +56 -0
  46. data/tests/test_app/.gitignore +18 -0
  47. data/tests/test_app/.rspec +1 -0
  48. data/tests/test_app/Gemfile +51 -0
  49. data/tests/test_app/README +256 -0
  50. data/tests/test_app/README.rdoc +261 -0
  51. data/tests/test_app/Rakefile +7 -0
  52. data/tests/test_app/app/assets/images/rails.png +0 -0
  53. data/tests/test_app/app/assets/javascripts/application.js +13 -0
  54. data/tests/test_app/app/assets/stylesheets/application.css +13 -0
  55. data/tests/test_app/app/controllers/application_controller.rb +8 -0
  56. data/tests/test_app/app/controllers/articles_controller.rb +18 -0
  57. data/tests/test_app/app/controllers/dummy_controller.rb +8 -0
  58. data/tests/test_app/app/controllers/posts_controller.rb +23 -0
  59. data/tests/test_app/app/controllers/profiles_controller.rb +14 -0
  60. data/tests/test_app/app/controllers/widgets_controller.rb +12 -0
  61. data/tests/test_app/app/helpers/application_helper.rb +2 -0
  62. data/tests/test_app/app/mailers/.gitkeep +0 -0
  63. data/tests/test_app/app/models/.gitkeep +0 -0
  64. data/tests/test_app/app/models/article.rb +3 -0
  65. data/tests/test_app/app/models/dummy.rb +7 -0
  66. data/tests/test_app/app/models/post.rb +3 -0
  67. data/tests/test_app/app/models/profile.rb +6 -0
  68. data/tests/test_app/app/models/user.rb +3 -0
  69. data/tests/test_app/app/models/widget.rb +3 -0
  70. data/tests/test_app/app/views/articles/index.html.erb +1 -0
  71. data/tests/test_app/app/views/articles/show.html.erb +1 -0
  72. data/tests/test_app/app/views/dummy/index.html.erb +0 -0
  73. data/tests/test_app/app/views/layouts/application.html.erb +14 -0
  74. data/tests/test_app/app/views/posts/edit.html.erb +0 -0
  75. data/tests/test_app/app/views/posts/index.html.erb +0 -0
  76. data/tests/test_app/app/views/posts/show.html.erb +0 -0
  77. data/tests/test_app/app/views/profiles/show.html.erb +3 -0
  78. data/tests/test_app/app/views/widgets/index.html.erb +0 -0
  79. data/tests/test_app/app/views/widgets/new.html.erb +0 -0
  80. data/tests/test_app/app/views/widgets/show.html.erb +0 -0
  81. data/tests/test_app/config/application.rb +59 -0
  82. data/tests/test_app/config/boot.rb +6 -0
  83. data/tests/test_app/config/cucumber.yml +8 -0
  84. data/tests/test_app/config/database.yml +30 -0
  85. data/tests/test_app/config/environment.rb +5 -0
  86. data/tests/test_app/config/environments/development.rb +37 -0
  87. data/tests/test_app/config/environments/pg_test.rb +35 -0
  88. data/tests/test_app/config/environments/production.rb +67 -0
  89. data/tests/test_app/config/environments/test.rb +37 -0
  90. data/tests/test_app/config/initializers/backtrace_silencers.rb +7 -0
  91. data/tests/test_app/config/initializers/impression.rb +8 -0
  92. data/tests/test_app/config/initializers/inflections.rb +15 -0
  93. data/tests/test_app/config/initializers/mime_types.rb +5 -0
  94. data/tests/test_app/config/initializers/secret_token.rb +7 -0
  95. data/tests/test_app/config/initializers/session_store.rb +8 -0
  96. data/tests/test_app/config/initializers/wrap_parameters.rb +14 -0
  97. data/tests/test_app/config/locales/en.yml +5 -0
  98. data/tests/test_app/config/routes.rb +4 -0
  99. data/tests/test_app/config.ru +4 -0
  100. data/tests/test_app/db/migrate/20110201153144_create_articles.rb +13 -0
  101. data/tests/test_app/db/migrate/20110210205028_create_posts.rb +13 -0
  102. data/tests/test_app/db/migrate/20111127184039_create_widgets.rb +15 -0
  103. data/tests/test_app/db/migrate/20130719024021_create_impressions_table.rb +32 -0
  104. data/tests/test_app/db/migrate/20150207135825_create_profiles.rb +10 -0
  105. data/tests/test_app/db/migrate/20150207140310_create_friendly_id_slugs.rb +18 -0
  106. data/tests/test_app/db/schema.rb +80 -0
  107. data/tests/test_app/db/seeds.rb +7 -0
  108. data/tests/test_app/lib/assets/.gitkeep +0 -0
  109. data/tests/test_app/lib/tasks/.gitkeep +0 -0
  110. data/tests/test_app/lib/tasks/cucumber.rake +53 -0
  111. data/tests/test_app/log/.gitkeep +0 -0
  112. data/tests/test_app/public/404.html +26 -0
  113. data/tests/test_app/public/422.html +26 -0
  114. data/tests/test_app/public/500.html +25 -0
  115. data/tests/test_app/public/favicon.ico +0 -0
  116. data/tests/test_app/public/images/rails.png +0 -0
  117. data/tests/test_app/public/index.html +241 -0
  118. data/tests/test_app/public/javascripts/application.js +2 -0
  119. data/tests/test_app/public/javascripts/controls.js +965 -0
  120. data/tests/test_app/public/javascripts/dragdrop.js +974 -0
  121. data/tests/test_app/public/javascripts/effects.js +1123 -0
  122. data/tests/test_app/public/javascripts/prototype.js +6001 -0
  123. data/tests/test_app/public/javascripts/rails.js +175 -0
  124. data/tests/test_app/public/robots.txt +5 -0
  125. data/tests/test_app/public/stylesheets/.gitkeep +0 -0
  126. data/tests/test_app/script/cucumber +10 -0
  127. data/tests/test_app/script/rails +6 -0
  128. data/tests/test_app/spec/controllers/articles_controller_spec.rb +76 -0
  129. data/tests/test_app/spec/controllers/dummy_controller_spec.rb +11 -0
  130. data/tests/test_app/spec/controllers/impressionist_uniqueness_spec.rb +396 -0
  131. data/tests/test_app/spec/controllers/posts_controller_spec.rb +28 -0
  132. data/tests/test_app/spec/controllers/widgets_controller_spec.rb +91 -0
  133. data/tests/test_app/spec/fixtures/articles.yml +3 -0
  134. data/tests/test_app/spec/fixtures/impressions.yml +43 -0
  135. data/tests/test_app/spec/fixtures/posts.yml +3 -0
  136. data/tests/test_app/spec/fixtures/profiles.yml +4 -0
  137. data/tests/test_app/spec/fixtures/widgets.yml +4 -0
  138. data/tests/test_app/spec/initializers/initializers_spec.rb +20 -0
  139. data/tests/test_app/spec/models/bots_spec.rb +27 -0
  140. data/tests/test_app/spec/models/counter_caching_spec.rb +51 -0
  141. data/tests/test_app/spec/models/model_spec.rb +70 -0
  142. data/tests/test_app/spec/rails_generators/rails_generators_spec.rb +23 -0
  143. data/tests/test_app/spec/spec_helper.rb +43 -0
  144. data/upgrade_migrations/version_0_3_0.rb +27 -0
  145. data/upgrade_migrations/version_0_4_0.rb +9 -0
  146. metadata +314 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7299ecfd37128db8e662cb4be2c69c264968f7b8
4
+ data.tar.gz: 7f86203d411036d87fe514868685beb07b67915d
5
+ SHA512:
6
+ metadata.gz: 4a31bbc1cf62ed5c0da878abb38dfcf1ef70b9747c432d3aa87d2413a911a767e0a7c750c20f942a00fd50a3e7525291c4add779b321216a69e2289a1eaf4bd3
7
+ data.tar.gz: d4477911efeacac44f762065709d6324f5b12121ee323ca11e1466c06aced8b5e5c3d6e5de11285945d1f628d670fc330d36665a31cfd31575da993c68433f2d
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ *~
2
+ /coverage
3
+ /pkg
4
+ /rdoc
5
+ /test_app/db/schema.rb
6
+ /test_app/db/migrate/*_create_impressions_table.rb
7
+ /test_app/doc
8
+ /test_app/test
9
+ /test_app/vendor
10
+ Gemfile.lock
11
+ gemfiles/*.lock
12
+ *.swo
13
+ *.swp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,26 @@
1
+ language: ruby
2
+ before_script:
3
+ - cd tests/test_app
4
+ - bundle exec rails g impressionist -f
5
+ - bundle exec rake db:create db:migrate RAILS_ENV=test
6
+ - cd ..
7
+ rvm:
8
+ - 1.9.3
9
+ - 2.0.0
10
+ - jruby-head
11
+ - rbx
12
+ - ruby-head
13
+ gemfile:
14
+ - gemfiles/rails32.gemfile
15
+ - gemfiles/rails40.gemfile
16
+ matrix:
17
+ allow_failures:
18
+ - rvm: jruby-head
19
+ - rvm: rbx
20
+ - rvm: ruby-head
21
+ fast_finish: true
22
+ notifications:
23
+ email:
24
+ - acnalesso@yahoo.co.uk
25
+ - john@couponshack.com
26
+ - mmcmahand@gmail.com
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,82 @@
1
+ == 1.5.1 (2016-08-24)
2
+ * Fixed #214
3
+ * (@xiaopow)
4
+
5
+ == 1.5.0 (2013-12-30)
6
+ * Added message filtering.
7
+ * (@overovermind)
8
+
9
+ == 1.4.8 (2013-09-01)
10
+ * Fixed #108
11
+ * Clean up
12
+ * (@acnalesso)
13
+
14
+ == 1.4.7 (2013-08-30)
15
+ * Fixed #103 - Allow impressions to be saved without a Model
16
+ * Fixed #104 - Wrong Documentation
17
+ * (@acnalesso)
18
+
19
+ == 1.4.6 (2013-08-17)
20
+ * Fixed 106
21
+ * Count unique records in Rails 4
22
+
23
+ == 1.4.5 (2013-07-17)
24
+ * Fixed update_counters raising an exception #97
25
+
26
+ == 1.4.4 (2013-07-15)
27
+ * Updated templates/impression.rb
28
+
29
+ == 1.4.3 (2013-07-15)
30
+ * Fixed Generators #96
31
+ * Remove pending tests, added tags
32
+
33
+ == 1.4.2 (2013-07-12)
34
+ * Added Mongoid Support
35
+ * Support Rails > 3.1 < 4.0
36
+ * Fixed #93
37
+ * Fixed travis failing
38
+ * Added two new entities
39
+ * Added MiniTest, testing against impressionist ( RSpec still testing test_app, will be removed soon)
40
+ * Clean up
41
+ * Moved all tests into tests dir
42
+
43
+ == 1.4.1 (2013-07-07)
44
+ * Added test support
45
+ * fix trailing space
46
+ * Created individually rspec files
47
+ * (@nbit001)
48
+
49
+ == 1.4.0 (2013-07-06)
50
+ * Fixed #92
51
+ * Pass option to unique for updatind counter_cache
52
+ * Clean up code, make it human readable
53
+ * Changed README in order to explain new features
54
+ * (@nbit001)
55
+
56
+ == 1.3.3 (2013-06-27)
57
+ * Added Rails4 Branch in order to support rails 4
58
+ * Rails 4 and Strong Parameters compability. (@bennick).
59
+
60
+ == 1.3.1 (non specified)
61
+ * Change controller_path back to controller_name (@johnmcaliley)
62
+
63
+
64
+ == 0.4.0 (2011-06-03)
65
+ * Fix postgres bug
66
+ * New impression count method that accepts options for filter, start_date and end_date
67
+ * Add referrer to Impression model. YOU MUST RUN THE UPGRADE MIGRATION IF YOU ARE UPGRADING FROM 0.3.0
68
+ * UPGRADE MIGRATION = impressionist/upgrade_migrations/version_0_4_0.rb
69
+ * NOTE IF YOU ARE UPGRADING FROM 0.2.5 OR BELOW, YOU MUST RUN BOTH UPGRADE MIGRATIONS
70
+
71
+ == 0.3.0 (2011-03-06)
72
+ * added session_hash to impression model
73
+ * migration template updated to add session_hash
74
+ * new count instance method for impressionable model - unique_impression_count_session
75
+ * NOTE: if you are upgrading from 0.2.5, then run the migration in the 'upgrade_migrations' dir
76
+
77
+ == 0.2.5 (2011-02-17)
78
+ * New model method - @widget.unique_impression_count_ip - This gives you unique impression account filtered by IP (and in turn request_hash since they have same IPs)
79
+ * @widget.unique_impression_count now uses request_hash. This was incorrectly stated in the README, since it was using ip_address. The README is correct as a result of the method change.
80
+
81
+ == 0.2.4 (2011-02-17)
82
+ * Fix issue #1 - action_name and controller_name were not being logged for impressionist method inside action
data/Gemfile ADDED
@@ -0,0 +1,26 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake', '>= 0.9'
4
+ gem 'rdoc', '>= 2.4.2'
5
+
6
+ platforms :jruby do
7
+ gem 'activerecord-jdbcsqlite3-adapter'
8
+ gem 'jdbc-sqlite3'
9
+ gem 'jruby-openssl'
10
+ end
11
+
12
+ platforms :ruby, :mswin, :mingw do
13
+ gem 'sqlite3'
14
+ end
15
+
16
+ group :test do
17
+ gem 'capybara', '>= 2.0.3'
18
+ gem 'minitest'
19
+ gem 'minitest-rails'
20
+ gem 'rails', '>= 3.2.15'
21
+ gem 'rspec-rails'
22
+ gem 'simplecov'
23
+ gem 'systemu'
24
+ end
25
+
26
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 cowboycoded
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,250 @@
1
+ ![Impressionist Logo](https://github.com/charlotte-ruby/impressionist/raw/master/logo.png)
2
+
3
+ [![Build Status](https://secure.travis-ci.org/charlotte-ruby/impressionist.png?branch=master)](http://travis-ci.org/charlotte-ruby/impressionist)
4
+ [![Code Climate](https://codeclimate.com/github/charlotte-ruby/impressionist.png)](https://codeclimate.com/github/charlotte-ruby/impressionist)
5
+
6
+ impressionist
7
+ =============
8
+
9
+ A lightweight plugin that logs impressions per action or manually per model
10
+
11
+ --------------------------------------------------------------------------------
12
+
13
+ What does this thing do?
14
+ ------------------------
15
+ Logs an impression... and I use that term loosely. It can log page impressions
16
+ (technically action impressions), but it is not limited to that. You can log
17
+ impressions multiple times per request. And you can also attach it to a model.
18
+ The goal of this project is to provide customizable stats that are immediately
19
+ accessible in your application as opposed to using Google Analytics and pulling
20
+ data using their API. You can attach custom messages to impressions. No
21
+ reporting yet.. this thingy just creates the data.
22
+
23
+ What about bots?
24
+ ----------------
25
+ They are ignored. 1200 known bots have been added to the ignore list as of
26
+ February 1, 2011. Impressionist uses this list:
27
+ http://www.user-agents.org/allagents.xml
28
+
29
+ Installation
30
+ ------------
31
+ Add it to your Gemfile
32
+
33
+ gem 'impressionist'
34
+
35
+ Install with Bundler
36
+
37
+ bundle install
38
+
39
+ Generate the impressions table migration
40
+
41
+ rails g impressionist
42
+
43
+ Run the migration
44
+
45
+ rake db:migrate
46
+
47
+ The following fields are provided in the migration:
48
+
49
+ t.string "impressionable_type" # model type: Widget
50
+ t.integer "impressionable_id" # model instance ID: @widget.id
51
+ t.integer "user_id" # automatically logs @current_user.id
52
+ t.string "controller_name" # logs the controller name
53
+ t.string "action_name" # logs the action_name
54
+ t.string "view_name" # TODO: log individual views (as well as partials and nested partials)
55
+ t.string "request_hash" # unique ID per request, in case you want to log multiple impressions and group them
56
+ t.string "session_hash" # logs the rails session
57
+ t.string "ip_address" # request.remote_ip
58
+ t.text "params" # request.params, except action name, controller name and resource id
59
+ t.string "referrer" # request.referer
60
+ t.string "message" # custom message you can add
61
+ t.datetime "created_at" # I am not sure what this is.... Any clue?
62
+ t.datetime "updated_at" # never seen this one before either.... Your guess is as good as mine?? ;-)
63
+
64
+ Usage
65
+ -----
66
+
67
+ 1. Log all actions in a controller
68
+
69
+ WidgetsController < ApplicationController
70
+ impressionist
71
+ end
72
+
73
+ 2. Specify actions you want logged in a controller
74
+
75
+ WidgetsController < ApplicationController
76
+ impressionist :actions=>[:show,:index]
77
+ end
78
+
79
+ 3. Make your models impressionable. This allows you to attach impressions to
80
+ an AR model instance. Impressionist will automatically log the Model name
81
+ (based on action_name) and the id (based on params[:id]), but in order to
82
+ get the count of impressions (example: @widget.impression_count), you will
83
+ need to make your model impressionable
84
+
85
+ class Widget < ActiveRecord::Base
86
+ is_impressionable
87
+ end
88
+
89
+ 4. Log an impression per model instance in your controller. Note that it is
90
+ not necessary to specify "impressionist" (usage #1) in the top of you
91
+ controller if you are using this method. If you add "impressionist" to the
92
+ top of your controller and also use this method in your action, it will
93
+ result in 2 impressions being logged (but associated with one request_hash).
94
+ If you're using [friendly_id](https://github.com/norman/friendly_id) be sure
95
+ to log impressionist this way, as params[:id] will return a string(url slug)
96
+ while impressionable_id is a Integer column in database.
97
+
98
+ def show
99
+ @widget = Widget.find
100
+ impressionist(@widget, "message...") # 2nd argument is optional
101
+ end
102
+
103
+ 5. Get unique impression count from a model. This groups impressions by
104
+ request_hash, so if you logged multiple impressions per request, it will
105
+ only count them one time. This unique impression count will not filter out
106
+ unique users, only unique requests
107
+
108
+ @widget.impressionist_count
109
+ @widget.impressionist_count(:start_date=>"2011-01-01",:end_date=>"2011-01-05")
110
+ @widget.impressionist_count(:start_date=>"2011-01-01") #specify start date only, end date = now
111
+
112
+ 6. Get the unique impression count from a model filtered by IP address. This
113
+ in turn will give you impressions with unique request_hash, since rows with
114
+ the same request_hash will have the same IP address.
115
+
116
+ @widget.impressionist_count(:filter=>:ip_address)
117
+
118
+ 7. Get the unique impression count from a model filtered by params. This
119
+ in turn will give you impressions with unique params.
120
+
121
+ @widget.impressionist_count(:filter => :params)
122
+
123
+ 8. Get the unique impression count from a model filtered by session hash. Same
124
+ as #6 regarding request hash. This may be more desirable than filtering by
125
+ IP address depending on your situation, since filtering by IP may ignore
126
+ visitors that use the same IP. The downside to this filtering is that a
127
+ user could clear session data in their browser and skew the results.
128
+
129
+ @widget.impressionist_count(:filter=>:session_hash)
130
+
131
+ 9. Get total impression count. This may return more than 1 impression per http
132
+ request, depending on how you are logging impressions
133
+
134
+ @widget.impressionist_count(:filter=>:all)
135
+
136
+ 10. Get impression count by message. This only counts impressions of the given message.
137
+
138
+ @widget.impressionist_count(:message=>"pageview", :filter=>:all)
139
+
140
+ Logging impressions for authenticated users happens automatically. If you have
141
+ a current_user helper or use @current_user in your before_filter to set your
142
+ authenticated user, current_user.id will be written to the user_id field in the
143
+ impressions table.
144
+
145
+ Adding a counter cache
146
+ ----------------------
147
+ Impressionist makes it easy to add a `counter_cache` column to your model. The
148
+ most basic configuration looks like:
149
+
150
+ is_impressionable :counter_cache => true
151
+
152
+ This will automatically increment the `impressions_count` column in the
153
+ included model. <b>Note: You'll need to add that column to your model. If you'd
154
+ like specific a different column name, you can:</b>
155
+
156
+ is_impressionable :counter_cache => true, :column_name => :my_column_name
157
+
158
+ If you'd like to include only unique impressions in your count:
159
+
160
+ # default will be filtered by ip_address
161
+ is_impressionable :counter_cache => true, :column_name => :my_column_name, :unique => true
162
+
163
+ If you'd like to specify what sort of unique impression you'd like to save? Fear not,
164
+ Any option you pass to unique, impressionist_count will use it as its filter to update_counters based on that unique option.
165
+
166
+ # options are any column in the impressions' table.
167
+ is_impressionable :counter_cache => true, :column_name => :my_column_name, :unique => :request_hash
168
+ is_impressionable :counter_cache => true, :column_name => :my_column_name, :unique => :all
169
+
170
+
171
+ Adding column to model
172
+ ----------------------
173
+ It is as simple as this:
174
+
175
+ t.integer :my_column_name, :default => 0
176
+
177
+ What if I only want to record unique impressions?
178
+ -------------------------------------------------
179
+ Maybe you only care about unique impressions and would like to avoid
180
+ unnecessary database records. You can specify conditions for recording
181
+ impressions in your controller:
182
+
183
+ # only record impression if the request has a unique combination of type, id, and session
184
+ impressionist :unique => [:impressionable_type, :impressionable_id, :session_hash]
185
+
186
+ # only record impression if the request has a unique combination of controller, action, and session
187
+ impressionist :unique => [:controller_name, :action_name, :session_hash]
188
+
189
+ # only record impression if session is unique
190
+ impressionist :unique => [:session_hash]
191
+
192
+ # only record impression if param is unique
193
+ impressionist :unique => [:params]
194
+
195
+ Or you can use the `impressionist` method directly:
196
+
197
+ impressionist(impressionable, "some message", :unique => [:session_hash])
198
+
199
+ Are you using Mongoid?
200
+ ---------------------
201
+
202
+ Execute this command on your terminal/console:
203
+
204
+ rails g impressionist --orm mongoid
205
+
206
+ This command create a file `impression.rb` on `config/initializer` folder. Add `config.orm = :mongoid` to this file:
207
+
208
+ # Use this hook to configure impressionist parameters
209
+ Impressionist.setup do |config|
210
+ # Define ORM. Could be :active_record (default), :mongo_mapper or :mongoid
211
+ # config.orm = :active_record
212
+ config.orm = :mongoid
213
+ end
214
+
215
+
216
+ Contributing to impressionist
217
+ -----------------------------
218
+ * Check out the latest master to make sure the feature hasn't been implemented
219
+ or the bug hasn't been fixed yet
220
+ * Check out the issue tracker to make sure someone already hasn't requested it
221
+ and/or contributed it
222
+ * Fork the project
223
+ * Start a feature/bugfix branch
224
+ * Commit and push until you are happy with your contribution
225
+ * Make sure to add rpsec tests for it. Patches or features without tests will
226
+ be ignored. Also, try to write better tests than I do ;-)
227
+ * If adding engine controller or view functionality, use HAML and Inherited
228
+ Resources.
229
+ * All testing is done inside a small Rails app (test_app). You will find specs
230
+ within this app.
231
+
232
+
233
+ Want to run the tests? Ok mummy
234
+ -------------------------------
235
+ * bundle install
236
+ * rails g impressionist
237
+ * rake db:migrate && rake db:test:prepare
238
+ * Run rake or rspec spec inside test_app dir
239
+ * nothing else.
240
+ * :wq
241
+
242
+ Contributors
243
+ ------------
244
+ * [johnmcaliley - creator](https://github.com/johnmcaliley)
245
+ * [Antonio C Nalesso - maintainer](https://github.com/acnalesso)
246
+ * [coryschires](https://github.com/coryschires)
247
+ * [georgmittendorfer](https://github.com/georgmittendorfer)
248
+
249
+
250
+ Copyright (c) 2011 John McAliley. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ require 'bundler/setup'
2
+ require 'rspec/core/rake_task'
3
+ require 'rake/testtask'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ # Impressionist will use MiniTest instead of RSpec
8
+ RSpec::Core::RakeTask.new do |task|
9
+ task.rspec_opts = "-I ./tests/test_app/spec"
10
+ task.pattern = "./tests/test_app/spec/**/*_spec.rb"
11
+ end
12
+
13
+ task :test_app => :spec
14
+ task :default => [:test, :test_app]
15
+
16
+ namespace :impressionist do
17
+ require File.dirname(__FILE__) + "/lib/impressionist/bots"
18
+
19
+ desc "output the list of bots from http://www.user-agents.org/"
20
+ task :bots do
21
+ p Impressionist::Bots.consume
22
+ end
23
+
24
+ end
25
+
26
+ # setup :test task to minitest
27
+ # Rake libs default is lib
28
+ # libs << path to load test_helper, etc..
29
+ Rake::TestTask.new do |t|
30
+ t.libs << "tests/spec"
31
+ t.pattern = "tests/spec/**/*_spec.rb"
32
+ t.test_files = FileList["tests/spec/**/*_spec.rb"]
33
+ t.verbose = true
34
+ end
@@ -0,0 +1,146 @@
1
+ require 'digest/sha2'
2
+
3
+ module ImpressionistController
4
+ module ClassMethods
5
+ def impressionist(opts={})
6
+ before_action { |c| c.impressionist_subapp_filter(opts) }
7
+ end
8
+ end
9
+
10
+ module InstanceMethods
11
+ def self.included(base)
12
+ base.before_action :impressionist_app_filter
13
+ end
14
+
15
+ def impressionist(obj,message=nil,opts={})
16
+ if should_count_impression?(opts)
17
+ if obj.respond_to?("impressionable?")
18
+ if unique_instance?(obj, opts[:unique])
19
+ obj.impressions.create(associative_create_statement({:message => message}))
20
+ end
21
+ else
22
+ # we could create an impression anyway. for classes, too. why not?
23
+ raise "#{obj.class.to_s} is not impressionable!"
24
+ end
25
+ end
26
+ end
27
+
28
+ def impressionist_app_filter
29
+ @impressionist_hash = Digest::SHA2.hexdigest(Time.now.to_f.to_s+rand(10000).to_s)
30
+ end
31
+
32
+ def impressionist_subapp_filter(opts = {})
33
+ if should_count_impression?(opts)
34
+ actions = opts[:actions]
35
+ actions.collect!{|a|a.to_s} unless actions.blank?
36
+ if (actions.blank? || actions.include?(action_name)) && unique?(opts[:unique])
37
+ Impression.create(direct_create_statement)
38
+ end
39
+ end
40
+ end
41
+
42
+ protected
43
+
44
+ # creates a statment hash that contains default values for creating an impression via an AR relation.
45
+ def associative_create_statement(query_params={})
46
+ query_params.reverse_merge!(
47
+ :controller_name => controller_name,
48
+ :action_name => action_name,
49
+ :user_id => user_id,
50
+ :request_hash => @impressionist_hash,
51
+ :session_hash => session_hash,
52
+ :ip_address => request.remote_ip,
53
+ :referrer => request.referer,
54
+ :params => params_hash
55
+ )
56
+ end
57
+
58
+ private
59
+
60
+ def bypass
61
+ Impressionist::Bots.bot?(request.user_agent)
62
+ end
63
+
64
+ def should_count_impression?(opts)
65
+ !bypass && condition_true?(opts[:if]) && condition_false?(opts[:unless])
66
+ end
67
+
68
+ def condition_true?(condition)
69
+ condition.present? ? conditional?(condition) : true
70
+ end
71
+
72
+ def condition_false?(condition)
73
+ condition.present? ? !conditional?(condition) : true
74
+ end
75
+
76
+ def conditional?(condition)
77
+ condition.is_a?(Symbol) ? self.send(condition) : condition.call
78
+ end
79
+
80
+ def unique_instance?(impressionable, unique_opts)
81
+ return unique_opts.blank? || !impressionable.impressions.where(unique_query(unique_opts, impressionable)).exists?
82
+ end
83
+
84
+ def unique?(unique_opts)
85
+ return unique_opts.blank? || check_impression?(unique_opts)
86
+ end
87
+
88
+ def check_impression?(unique_opts)
89
+ impressions = Impression.where(unique_query(unique_opts - [:params]))
90
+ check_unique_impression?(impressions, unique_opts)
91
+ end
92
+
93
+ def check_unique_impression?(impressions, unique_opts)
94
+ impressions_present = impressions.exists?
95
+ impressions_present && unique_opts_has_params?(unique_opts) ? check_unique_with_params?(impressions) : !impressions_present
96
+ end
97
+
98
+ def unique_opts_has_params?(unique_opts)
99
+ unique_opts.include?(:params)
100
+ end
101
+
102
+ def check_unique_with_params?(impressions)
103
+ request_param = params_hash
104
+ impressions.detect{|impression| impression.params == request_param }.nil?
105
+ end
106
+
107
+ # creates the query to check for uniqueness
108
+ def unique_query(unique_opts,impressionable=nil)
109
+ full_statement = direct_create_statement({},impressionable)
110
+ # reduce the full statement to the params we need for the specified unique options
111
+ unique_opts.reduce({}) do |query, param|
112
+ query[param] = full_statement[param]
113
+ query
114
+ end
115
+ end
116
+
117
+ # creates a statment hash that contains default values for creating an impression.
118
+ def direct_create_statement(query_params={},impressionable=nil)
119
+ query_params.reverse_merge!(
120
+ :impressionable_type => controller_name.singularize.camelize,
121
+ :impressionable_id => impressionable.present? ? impressionable.id : params[:id]
122
+ )
123
+ associative_create_statement(query_params)
124
+ end
125
+
126
+ def session_hash
127
+ # # careful: request.session_options[:id] encoding in rspec test was ASCII-8BIT
128
+ # # that broke the database query for uniqueness. not sure if this is a testing only issue.
129
+ # str = request.session_options[:id]
130
+ # logger.debug "Encoding: #{str.encoding.inspect}"
131
+ # # request.session_options[:id].encode("ISO-8859-1")
132
+ request.session_options[:id]
133
+ end
134
+
135
+ def params_hash
136
+ request.params.except(:controller, :action, :id)
137
+ end
138
+
139
+ #use both @current_user and current_user helper
140
+ def user_id
141
+ user_id = @current_user ? @current_user.id : nil rescue nil
142
+ user_id = current_user ? current_user.id : nil rescue nil if user_id.blank?
143
+ user_id
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,2 @@
1
+ class Impression
2
+ end