impressionist-cody 2.0.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.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +25 -0
  3. data/.gitignore +17 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +27 -0
  6. data/.rubocop_todo.yml +660 -0
  7. data/CHANGELOG.rdoc +96 -0
  8. data/Gemfile +22 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +265 -0
  11. data/Rakefile +20 -0
  12. data/UPGRADE_GUIDE.md +13 -0
  13. data/app/assets/config/manifest.js +3 -0
  14. data/app/controllers/impressionist_controller.rb +166 -0
  15. data/app/models/impression.rb +2 -0
  16. data/app/models/impressionist/bots.rb +1468 -0
  17. data/app/models/impressionist/impressionable.rb +62 -0
  18. data/impressionist.gemspec +30 -0
  19. data/lib/generators/active_record/impressionist_generator.rb +22 -0
  20. data/lib/generators/active_record/templates/create_impressions_table.rb.erb +32 -0
  21. data/lib/generators/impressionist_generator.rb +13 -0
  22. data/lib/generators/mongo_mapper/impressionist_generator.rb +8 -0
  23. data/lib/generators/mongoid/impressionist_generator.rb +8 -0
  24. data/lib/generators/templates/impression.rb.erb +8 -0
  25. data/lib/impressionist/bots.rb +21 -0
  26. data/lib/impressionist/controllers/mongoid/impressionist_controller.rb +10 -0
  27. data/lib/impressionist/counter_cache.rb +76 -0
  28. data/lib/impressionist/engine.rb +45 -0
  29. data/lib/impressionist/is_impressionable.rb +23 -0
  30. data/lib/impressionist/load.rb +11 -0
  31. data/lib/impressionist/models/active_record/impression.rb +14 -0
  32. data/lib/impressionist/models/active_record/impressionist/impressionable.rb +12 -0
  33. data/lib/impressionist/models/mongo_mapper/impression.rb +18 -0
  34. data/lib/impressionist/models/mongo_mapper/impressionist/impressionable.rb +21 -0
  35. data/lib/impressionist/models/mongoid/impression.rb +26 -0
  36. data/lib/impressionist/models/mongoid/impressionist/impressionable.rb +28 -0
  37. data/lib/impressionist/rails_toggle.rb +26 -0
  38. data/lib/impressionist/setup_association.rb +53 -0
  39. data/lib/impressionist/update_counters.rb +77 -0
  40. data/lib/impressionist/version.rb +3 -0
  41. data/lib/impressionist.rb +12 -0
  42. data/logo.png +0 -0
  43. data/spec/controllers/articles_controller_spec.rb +113 -0
  44. data/spec/controllers/dummy_controller_spec.rb +13 -0
  45. data/spec/controllers/impressionist_uniqueness_spec.rb +463 -0
  46. data/spec/controllers/posts_controller_spec.rb +36 -0
  47. data/spec/controllers/widgets_controller_spec.rb +103 -0
  48. data/spec/counter_caching_spec.rb +49 -0
  49. data/spec/dummy/.ruby-version +1 -0
  50. data/spec/dummy/Rakefile +6 -0
  51. data/spec/dummy/app/assets/config/manifest.js +1 -0
  52. data/spec/dummy/app/assets/images/.keep +0 -0
  53. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  54. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  55. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  56. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  57. data/spec/dummy/app/controllers/articles_controller.rb +22 -0
  58. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  59. data/spec/dummy/app/controllers/dummy_controller.rb +6 -0
  60. data/spec/dummy/app/controllers/posts_controller.rb +23 -0
  61. data/spec/dummy/app/controllers/profiles_controller.rb +14 -0
  62. data/spec/dummy/app/controllers/widgets_controller.rb +12 -0
  63. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  64. data/spec/dummy/app/javascript/packs/application.js +15 -0
  65. data/spec/dummy/app/jobs/application_job.rb +7 -0
  66. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  67. data/spec/dummy/app/models/application_record.rb +3 -0
  68. data/spec/dummy/app/models/article.rb +3 -0
  69. data/spec/dummy/app/models/concerns/.keep +0 -0
  70. data/spec/dummy/app/models/dummy.rb +7 -0
  71. data/spec/dummy/app/models/post.rb +3 -0
  72. data/spec/dummy/app/models/profile.rb +6 -0
  73. data/spec/dummy/app/models/user.rb +3 -0
  74. data/spec/dummy/app/models/widget.rb +3 -0
  75. data/spec/dummy/app/views/articles/index.html.erb +1 -0
  76. data/spec/dummy/app/views/articles/show.html.erb +1 -0
  77. data/spec/dummy/app/views/dummy/index.html.erb +0 -0
  78. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  79. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  80. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  81. data/spec/dummy/app/views/posts/edit.html.erb +0 -0
  82. data/spec/dummy/app/views/posts/index.html.erb +0 -0
  83. data/spec/dummy/app/views/posts/show.html.erb +0 -0
  84. data/spec/dummy/app/views/profiles/show.html.erb +3 -0
  85. data/spec/dummy/app/views/widgets/index.html.erb +0 -0
  86. data/spec/dummy/app/views/widgets/new.html.erb +0 -0
  87. data/spec/dummy/app/views/widgets/show.html.erb +0 -0
  88. data/spec/dummy/bin/rails +4 -0
  89. data/spec/dummy/bin/rake +4 -0
  90. data/spec/dummy/bin/setup +33 -0
  91. data/spec/dummy/config/application.rb +20 -0
  92. data/spec/dummy/config/boot.rb +5 -0
  93. data/spec/dummy/config/cable.yml +10 -0
  94. data/spec/dummy/config/database.yml +25 -0
  95. data/spec/dummy/config/environment.rb +5 -0
  96. data/spec/dummy/config/environments/development.rb +62 -0
  97. data/spec/dummy/config/environments/production.rb +112 -0
  98. data/spec/dummy/config/environments/test.rb +49 -0
  99. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  100. data/spec/dummy/config/initializers/assets.rb +12 -0
  101. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  102. data/spec/dummy/config/initializers/content_security_policy.rb +28 -0
  103. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  104. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  105. data/spec/dummy/config/initializers/impression.rb +8 -0
  106. data/spec/dummy/config/initializers/inflections.rb +16 -0
  107. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  108. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  109. data/spec/dummy/config/locales/en.yml +33 -0
  110. data/spec/dummy/config/puma.rb +38 -0
  111. data/spec/dummy/config/routes.rb +4 -0
  112. data/spec/dummy/config/spring.rb +6 -0
  113. data/spec/dummy/config/storage.yml +34 -0
  114. data/spec/dummy/config.ru +5 -0
  115. data/spec/dummy/config.ru2 +4 -0
  116. data/spec/dummy/db/development.sqlite3 +0 -0
  117. data/spec/dummy/db/migrate/20110201153144_create_articles.rb +13 -0
  118. data/spec/dummy/db/migrate/20110210205028_create_posts.rb +13 -0
  119. data/spec/dummy/db/migrate/20111127184039_create_widgets.rb +15 -0
  120. data/spec/dummy/db/migrate/20150207135825_create_profiles.rb +10 -0
  121. data/spec/dummy/db/migrate/20150207140310_create_friendly_id_slugs.rb +18 -0
  122. data/spec/dummy/db/migrate/20200720143817_create_impressions_table.rb +32 -0
  123. data/spec/dummy/db/schema.rb +77 -0
  124. data/spec/dummy/lib/assets/.keep +0 -0
  125. data/spec/dummy/log/.keep +0 -0
  126. data/spec/dummy/log/development.log +129 -0
  127. data/spec/dummy/public/404.html +67 -0
  128. data/spec/dummy/public/422.html +67 -0
  129. data/spec/dummy/public/500.html +66 -0
  130. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  131. data/spec/dummy/public/apple-touch-icon.png +0 -0
  132. data/spec/dummy/public/favicon.ico +0 -0
  133. data/spec/dummy/storage/.keep +0 -0
  134. data/spec/fixtures/articles.yml +3 -0
  135. data/spec/fixtures/impressions.yml +43 -0
  136. data/spec/fixtures/posts.yml +3 -0
  137. data/spec/fixtures/profiles.yml +4 -0
  138. data/spec/fixtures/widgets.yml +4 -0
  139. data/spec/initializers_spec.rb +21 -0
  140. data/spec/models/bots_spec.rb +25 -0
  141. data/spec/models/impression_spec.rb +66 -0
  142. data/spec/rails_generators/rails_generators_spec.rb +23 -0
  143. data/spec/rails_helper.rb +11 -0
  144. data/spec/rails_toggle_spec.rb +31 -0
  145. data/spec/setup_association_spec.rb +48 -0
  146. data/spec/spec_helper.rb +43 -0
  147. data/upgrade_migrations/version_0_3_0.rb +27 -0
  148. data/upgrade_migrations/version_0_4_0.rb +9 -0
  149. data/upgrade_migrations/version_1_5_2.rb +12 -0
  150. metadata +302 -0
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,96 @@
1
+ == 1.6.1 (2018-04-16)
2
+ * Add belongs_to optional true to setup_association (#264, @josephMG)
3
+ * Add missing field for Mongoid (#254, @Fibrasek)
4
+ * Implemented patch that will add the Rails major version to the migration file (#248, @jordanhudgens)
5
+ * Add params filtering on new column (#246, @rposborne)
6
+ * Add a DB migration to add params to schema. (#245, @rposborne)
7
+
8
+ == 1.6.0 (2017-05-24)
9
+ * Documentation example for counter_cache (#239, @fwolfst)
10
+ * Green Travis CI builds (#238, @jgrau)
11
+ * Rails 5.1 support (#241, @msimonborg)
12
+ * Use `dependent: :delete_all` instead of `:destroy` for performance gains (#242, @midnightSuyama & @jgrau)
13
+ * Fix counter cache not updating when no `unique` option is set (#243, @sachiotomita & @jgrau)
14
+
15
+ == 1.5.2 (2016-09-16)
16
+
17
+ == 1.5.1 (2013-12-31)
18
+
19
+ == 1.5.0 (2013-12-30)
20
+ * Added message filtering.
21
+ * (@overovermind)
22
+
23
+ == 1.4.8 (2013-09-01)
24
+ * Fixed #108
25
+ * Clean up
26
+ * (@acnalesso)
27
+
28
+ == 1.4.7 (2013-08-30)
29
+ * Fixed #103 - Allow impressions to be saved without a Model
30
+ * Fixed #104 - Wrong Documentation
31
+ * (@acnalesso)
32
+
33
+ == 1.4.6 (2013-08-17)
34
+ * Fixed 106
35
+ * Count unique records in Rails 4
36
+
37
+ == 1.4.5 (2013-07-17)
38
+ * Fixed update_counters raising an exception #97
39
+
40
+ == 1.4.4 (2013-07-15)
41
+ * Updated templates/impression.rb
42
+
43
+ == 1.4.3 (2013-07-15)
44
+ * Fixed Generators #96
45
+ * Remove pending tests, added tags
46
+
47
+ == 1.4.2 (2013-07-12)
48
+ * Added Mongoid Support
49
+ * Support Rails > 3.1 < 4.0
50
+ * Fixed #93
51
+ * Fixed travis failing
52
+ * Added two new entities
53
+ * Added MiniTest, testing against impressionist ( RSpec still testing test_app, will be removed soon)
54
+ * Clean up
55
+ * Moved all tests into tests dir
56
+
57
+ == 1.4.1 (2013-07-07)
58
+ * Added test support
59
+ * fix trailing space
60
+ * Created individually rspec files
61
+ * (@nbit001)
62
+
63
+ == 1.4.0 (2013-07-06)
64
+ * Fixed #92
65
+ * Pass option to unique for updatind counter_cache
66
+ * Clean up code, make it human readable
67
+ * Changed README in order to explain new features
68
+ * (@nbit001)
69
+
70
+ == 1.3.3 (2013-06-27)
71
+ * Added Rails4 Branch in order to support rails 4
72
+ * Rails 4 and Strong Parameters compability. (@bennick).
73
+
74
+ == 1.3.1 (non specified)
75
+ * Change controller_path back to controller_name (@johnmcaliley)
76
+
77
+
78
+ == 0.4.0 (2011-06-03)
79
+ * Fix postgres bug
80
+ * New impression count method that accepts options for filter, start_date and end_date
81
+ * Add referrer to Impression model. YOU MUST RUN THE UPGRADE MIGRATION IF YOU ARE UPGRADING FROM 0.3.0
82
+ * UPGRADE MIGRATION = impressionist/upgrade_migrations/version_0_4_0.rb
83
+ * NOTE IF YOU ARE UPGRADING FROM 0.2.5 OR BELOW, YOU MUST RUN BOTH UPGRADE MIGRATIONS
84
+
85
+ == 0.3.0 (2011-03-06)
86
+ * added session_hash to impression model
87
+ * migration template updated to add session_hash
88
+ * new count instance method for impressionable model - unique_impression_count_session
89
+ * NOTE: if you are upgrading from 0.2.5, then run the migration in the 'upgrade_migrations' dir
90
+
91
+ == 0.2.5 (2011-02-17)
92
+ * 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)
93
+ * @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.
94
+
95
+ == 0.2.4 (2011-02-17)
96
+ * Fix issue #1 - action_name and controller_name were not being logged for impressionist method inside action
data/Gemfile ADDED
@@ -0,0 +1,22 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake', '>= 12.3.3'
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
+ group :test do
13
+ gem 'minitest'
14
+ gem 'pry'
15
+ gem 'rspec', "~> 3.0"
16
+ gem 'rubocop-rails', require: false
17
+ gem 'rubocop-rspec', require: false
18
+ gem 'simplecov'
19
+ gem 'systemu'
20
+ end
21
+
22
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2018 github.com/johnmcaliley
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,265 @@
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
+ WE ARE LOOKING FOR MAINTAINERS. CONTACT @johnmcaliley IF YOU ARE INTERESTED IN HELPING
7
+ =======================================================================================
8
+
9
+ impressionist
10
+ =============
11
+
12
+ A lightweight plugin that logs impressions per action or manually per model
13
+
14
+ --------------------------------------------------------------------------------
15
+
16
+ What does this thing do?
17
+ ------------------------
18
+ Logs an impression... and I use that term loosely. It can log page impressions
19
+ (technically action impressions), but it is not limited to that. You can log
20
+ impressions multiple times per request. And you can also attach it to a model.
21
+ The goal of this project is to provide customizable stats that are immediately
22
+ accessible in your application as opposed to using Google Analytics and pulling
23
+ data using their API. You can attach custom messages to impressions. No
24
+ reporting yet.. this thingy just creates the data.
25
+
26
+ What about bots?
27
+ ----------------
28
+ They are ignored. 1200 known bots have been added to the ignore list as of
29
+ February 1, 2011. Impressionist uses this list:
30
+ http://www.user-agents.org/allagents.xml
31
+
32
+ Installation
33
+ ------------
34
+ Add it to your Gemfile
35
+
36
+ #rails 6
37
+ gem 'impressionist'
38
+
39
+ #rails 5 or lower
40
+ gem 'impressionist', '~>1.6.1'
41
+
42
+ Install with Bundler
43
+
44
+ bundle install
45
+
46
+ Generate the impressions table migration
47
+
48
+ rails g impressionist
49
+
50
+ Run the migration
51
+
52
+ rake db:migrate
53
+
54
+ The following fields are provided in the migration:
55
+
56
+ t.string "impressionable_type" # model type: Widget
57
+ t.integer "impressionable_id" # model instance ID: @widget.id
58
+ t.integer "user_id" # automatically logs @current_user.id
59
+ t.string "controller_name" # logs the controller name
60
+ t.string "action_name" # logs the action_name
61
+ t.string "view_name" # TODO: log individual views (as well as partials and nested partials)
62
+ t.string "request_hash" # unique ID per request, in case you want to log multiple impressions and group them
63
+ t.string "session_hash" # logs the rails session
64
+ t.string "ip_address" # request.remote_ip
65
+ t.text "params" # request.params, except action name, controller name and resource id
66
+ t.string "referrer" # request.referer
67
+ t.string "message" # custom message you can add
68
+ t.datetime "created_at" # I am not sure what this is.... Any clue?
69
+ t.datetime "updated_at" # never seen this one before either.... Your guess is as good as mine?? ;-)
70
+
71
+ Usage
72
+ -----
73
+
74
+ 1. Log all actions in a controller
75
+
76
+ WidgetsController < ApplicationController
77
+ impressionist
78
+ end
79
+
80
+ 2. Specify actions you want logged in a controller
81
+
82
+ WidgetsController < ApplicationController
83
+ impressionist :actions=>[:show,:index]
84
+ end
85
+
86
+ 3. Make your models impressionable. This allows you to attach impressions to
87
+ an AR model instance. Impressionist will automatically log the Model name
88
+ (based on action_name) and the id (based on params[:id]), but in order to
89
+ get the count of impressions (example: @widget.impression_count), you will
90
+ need to make your model impressionable
91
+
92
+ class Widget < ActiveRecord::Base
93
+ is_impressionable
94
+ end
95
+
96
+ 4. Log an impression per model instance in your controller. Note that it is
97
+ not necessary to specify "impressionist" (usage #1) in the top of you
98
+ controller if you are using this method. If you add "impressionist" to the
99
+ top of your controller and also use this method in your action, it will
100
+ result in 2 impressions being logged (but associated with one request_hash).
101
+ If you're using [friendly_id](https://github.com/norman/friendly_id) be sure
102
+ to log impressionist this way, as params[:id] will return a string(url slug)
103
+ while impressionable_id is a Integer column in database. Also note that you
104
+ have to take step #3 for the Widget model for this to work.
105
+
106
+ def show
107
+ @widget = Widget.find
108
+ impressionist(@widget, "message...") # 2nd argument is optional
109
+ end
110
+
111
+ 5. Get unique impression count from a model. This groups impressions by
112
+ request_hash, so if you logged multiple impressions per request, it will
113
+ only count them one time. This unique impression count will not filter out
114
+ unique users, only unique requests
115
+
116
+ @widget.impressionist_count
117
+ @widget.impressionist_count(:start_date=>"2011-01-01",:end_date=>"2011-01-05")
118
+ @widget.impressionist_count(:start_date=>"2011-01-01") #specify start date only, end date = now
119
+
120
+ 6. Get the unique impression count from a model filtered by IP address. This
121
+ in turn will give you impressions with unique request_hash, since rows with
122
+ the same request_hash will have the same IP address.
123
+
124
+ @widget.impressionist_count(:filter=>:ip_address)
125
+
126
+ 7. Get the unique impression count from a model filtered by params. This
127
+ in turn will give you impressions with unique params.
128
+
129
+ @widget.impressionist_count(:filter => :params)
130
+
131
+ 8. Get the unique impression count from a model filtered by session hash. Same
132
+ as #6 regarding request hash. This may be more desirable than filtering by
133
+ IP address depending on your situation, since filtering by IP may ignore
134
+ visitors that use the same IP. The downside to this filtering is that a
135
+ user could clear session data in their browser and skew the results.
136
+
137
+ @widget.impressionist_count(:filter=>:session_hash)
138
+
139
+ 9. Get total impression count. This may return more than 1 impression per http
140
+ request, depending on how you are logging impressions
141
+
142
+ @widget.impressionist_count(:filter=>:all)
143
+
144
+ 10. Get impression count by message. This only counts impressions of the given message.
145
+
146
+ @widget.impressionist_count(:message=>"pageview", :filter=>:all)
147
+
148
+ Logging impressions for authenticated users happens automatically. If you have
149
+ a current_user helper or use @current_user in your before_filter (or before_action in Rails >= 5.0) to set your
150
+ authenticated user, current_user.id will be written to the user_id field in the
151
+ impressions table.
152
+
153
+ Adding a counter cache
154
+ ----------------------
155
+ Impressionist makes it easy to add a `counter_cache` column to your model. The
156
+ most basic configuration looks like:
157
+
158
+ is_impressionable :counter_cache => true
159
+
160
+ This will automatically increment the `impressions_count` column in the
161
+ included model. <b>Note: You'll need to add that column to your model. If you'd
162
+ like specific a different column name, you can:</b>
163
+
164
+ is_impressionable :counter_cache => true, :column_name => :my_column_name
165
+
166
+ If you'd like to include only unique impressions in your count:
167
+
168
+ # default will be filtered by ip_address
169
+ is_impressionable :counter_cache => true, :column_name => :my_column_name, :unique => true
170
+
171
+ If you'd like to specify what sort of unique impression you'd like to save? Fear not,
172
+ Any option you pass to unique, impressionist_count will use it as its filter to update_counters based on that unique option.
173
+
174
+ # options are any column in the impressions' table.
175
+ is_impressionable :counter_cache => true, :column_name => :my_column_name, :unique => :request_hash
176
+ is_impressionable :counter_cache => true, :column_name => :my_column_name, :unique => :all
177
+
178
+
179
+ Adding column to model
180
+ ----------------------
181
+ It is as simple as this:
182
+
183
+ t.integer :my_column_name, :default => 0
184
+
185
+ If you want to use the typical Rails 4 migration generator, you can:
186
+
187
+ rails g migration AddImpressionsCountToBook impressions_count:int
188
+
189
+ What if I only want to record unique impressions?
190
+ -------------------------------------------------
191
+ Maybe you only care about unique impressions and would like to avoid
192
+ unnecessary database records. You can specify conditions for recording
193
+ impressions in your controller:
194
+
195
+ # only record impression if the request has a unique combination of type, id, and session
196
+ impressionist :unique => [:impressionable_type, :impressionable_id, :session_hash]
197
+
198
+ # only record impression if the request has a unique combination of controller, action, and session
199
+ impressionist :unique => [:controller_name, :action_name, :session_hash]
200
+
201
+ # only record impression if session is unique
202
+ impressionist :unique => [:session_hash]
203
+
204
+ # only record impression if param is unique
205
+ impressionist :unique => [:params]
206
+
207
+ Or you can use the `impressionist` method directly:
208
+
209
+ impressionist(impressionable, "some message", :unique => [:session_hash])
210
+
211
+ Are you using Mongoid?
212
+ ---------------------
213
+
214
+ Execute this command on your terminal/console:
215
+
216
+ rails g impressionist --orm mongoid
217
+
218
+ This command create a file `impression.rb` on `config/initializer` folder. Add `config.orm = :mongoid` to this file:
219
+
220
+ # Use this hook to configure impressionist parameters
221
+ Impressionist.setup do |config|
222
+ # Define ORM. Could be :active_record (default), :mongo_mapper or :mongoid
223
+ # config.orm = :active_record
224
+ config.orm = :mongoid
225
+ end
226
+
227
+
228
+ Contributing to impressionist
229
+ -----------------------------
230
+ * Check out the latest master to make sure the feature hasn't been implemented
231
+ or the bug hasn't been fixed yet
232
+ * Check out the issue tracker to make sure someone already hasn't requested it
233
+ and/or contributed it
234
+ * Fork the project
235
+ * Start a feature/bugfix branch
236
+ * Commit and push until you are happy with your contribution
237
+ * Make sure to add rpsec tests for it. Patches or features without tests will
238
+ be ignored. Also, try to write better tests than I do ;-)
239
+ * If adding engine controller or view functionality, use HAML and Inherited
240
+ Resources.
241
+ * All testing is done inside a small Rails app (test_app). You will find specs
242
+ within this app.
243
+
244
+
245
+ Want to run the tests? Ok mummy
246
+ -------------------------------
247
+ * bundle install
248
+ * rails g impressionist
249
+ * rake db:migrate && rake db:test:prepare
250
+ * Run rake or rspec spec inside test_app dir
251
+ * nothing else.
252
+ * :wq
253
+
254
+ Contributors
255
+ ------------
256
+ WE ARE CURRENTLY LOOKING FOR SOMEONE TO HELP MAINTAIN THIS REPOSITORY. IF YOU ARE INTERESTED, MESSAGE @johnmcaliley.
257
+
258
+ * [johnmcaliley - creator](https://github.com/johnmcaliley)
259
+ * [jgrau](https://github.com/jgrau)
260
+ * [acnalesso](https://github.com/acnalesso)
261
+ * [coryschires](https://github.com/coryschires)
262
+ * [georgmittendorfer](https://github.com/georgmittendorfer)
263
+
264
+
265
+ Copyright (c) 2011 John McAliley. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'rspec'
4
+ require 'rspec/core/rake_task'
5
+ require 'rake/testtask'
6
+
7
+
8
+ RSpec::Core::RakeTask.new(:spec)
9
+ task default: :spec
10
+
11
+ Bundler::GemHelper.install_tasks
12
+
13
+ namespace :impressionist do
14
+ require "#{File.dirname(__FILE__)}/lib/impressionist/bots"
15
+
16
+ desc "output the list of bots from http://www.user-agents.org/"
17
+ task :bots do
18
+ p Impressionist::Bots.consume
19
+ end
20
+ end
data/UPGRADE_GUIDE.md ADDED
@@ -0,0 +1,13 @@
1
+ # Upgrade guide
2
+
3
+ ## v1.5.1 -> v1.5.2
4
+
5
+ Version 1.5.2 adds are new column to the `impressions` table. If you're on v1.5.1 you need to manually add the new column using
6
+
7
+ ```
8
+ add_column :impressions, :params, :text
9
+
10
+ add_index :impressions, [:impressionable_type, :impressionable_id, :params], :name => "poly_params_request_index", :unique => false
11
+ ```
12
+
13
+ before upgrading.
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,166 @@
1
+ require 'digest/sha2'
2
+
3
+
4
+ module ImpressionistController
5
+ module ClassMethods
6
+ def impressionist(opts={})
7
+ if Rails::VERSION::MAJOR >= 5
8
+ before_action { |c| c.impressionist_subapp_filter(opts) }
9
+ else
10
+ before_filter { |c| c.impressionist_subapp_filter(opts) }
11
+ end
12
+ end
13
+ end
14
+
15
+ module InstanceMethods
16
+ def self.included(base)
17
+ if Rails::VERSION::MAJOR >= 5
18
+ base.before_action :impressionist_app_filter
19
+ else
20
+ base.before_filter :impressionist_app_filter
21
+ end
22
+ end
23
+
24
+ def impressionist(obj,message=nil,opts={})
25
+ if should_count_impression?(opts)
26
+ if obj.respond_to?("impressionable?")
27
+ if unique_instance?(obj, opts[:unique])
28
+ obj.impressions.create(associative_create_statement({:message => message}))
29
+ end
30
+ else
31
+ # we could create an impression anyway. for classes, too. why not?
32
+ raise "#{obj.class.to_s} is not impressionable!"
33
+ end
34
+ end
35
+ end
36
+
37
+ def impressionist_app_filter
38
+ @impressionist_hash = Digest::SHA2.hexdigest(Time.now.to_f.to_s+rand(10000).to_s)
39
+ end
40
+
41
+ def impressionist_subapp_filter(opts = {})
42
+ if should_count_impression?(opts)
43
+ actions = opts[:actions]
44
+ actions.collect!{|a|a.to_s} unless actions.blank?
45
+ if (actions.blank? || actions.include?(action_name)) && unique?(opts[:unique])
46
+ Impression.create(direct_create_statement)
47
+ end
48
+ end
49
+ end
50
+
51
+ protected
52
+
53
+ # creates a statment hash that contains default values for creating an impression via an AR relation.
54
+ def associative_create_statement(query_params={})
55
+ # support older versions of rails:
56
+ # see https://github.com/rails/rails/pull/34039
57
+ if Rails::VERSION::MAJOR < 6
58
+ filter = ActionDispatch::Http::ParameterFilter.new(Rails.application.config.filter_parameters)
59
+ else
60
+ filter = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
61
+ end
62
+
63
+ query_params.reverse_merge!(
64
+ :controller_name => controller_name,
65
+ :action_name => action_name,
66
+ :user_id => user_id,
67
+ :request_hash => @impressionist_hash,
68
+ :session_hash => session_hash,
69
+ :ip_address => request.remote_ip,
70
+ :referrer => request.referer,
71
+ :params => filter.filter(params_hash)
72
+ )
73
+ end
74
+
75
+ private
76
+
77
+ def bypass
78
+ Impressionist::Bots.bot?(request.user_agent)
79
+ end
80
+
81
+ def should_count_impression?(opts)
82
+ !bypass && condition_true?(opts[:if]) && condition_false?(opts[:unless])
83
+ end
84
+
85
+ def condition_true?(condition)
86
+ condition.present? ? conditional?(condition) : true
87
+ end
88
+
89
+ def condition_false?(condition)
90
+ condition.present? ? !conditional?(condition) : true
91
+ end
92
+
93
+ def conditional?(condition)
94
+ condition.is_a?(Symbol) ? self.send(condition) : condition.call
95
+ end
96
+
97
+ def unique_instance?(impressionable, unique_opts)
98
+ return unique_opts.blank? || !impressionable.impressions.where(unique_query(unique_opts, impressionable)).exists?
99
+ end
100
+
101
+ def unique?(unique_opts)
102
+ return unique_opts.blank? || check_impression?(unique_opts)
103
+ end
104
+
105
+ def check_impression?(unique_opts)
106
+ impressions = Impression.where(unique_query(unique_opts - [:params]))
107
+ check_unique_impression?(impressions, unique_opts)
108
+ end
109
+
110
+ def check_unique_impression?(impressions, unique_opts)
111
+ impressions_present = impressions.exists?
112
+ impressions_present && unique_opts_has_params?(unique_opts) ? check_unique_with_params?(impressions) : !impressions_present
113
+ end
114
+
115
+ def unique_opts_has_params?(unique_opts)
116
+ unique_opts.include?(:params)
117
+ end
118
+
119
+ def check_unique_with_params?(impressions)
120
+ request_param = params_hash
121
+ impressions.detect{|impression| impression.params == request_param }.nil?
122
+ end
123
+
124
+ # creates the query to check for uniqueness
125
+ def unique_query(unique_opts,impressionable=nil)
126
+ full_statement = direct_create_statement({},impressionable)
127
+ # reduce the full statement to the params we need for the specified unique options
128
+ unique_opts.reduce({}) do |query, param|
129
+ query[param] = full_statement[param]
130
+ query
131
+ end
132
+ end
133
+
134
+ # creates a statment hash that contains default values for creating an impression.
135
+ def direct_create_statement(query_params={},impressionable=nil)
136
+ query_params.reverse_merge!(
137
+ :impressionable_type => controller_name.singularize.camelize,
138
+ :impressionable_id => impressionable.present? ? impressionable.id : params[:id]
139
+ )
140
+ associative_create_statement(query_params)
141
+ end
142
+
143
+ def session_hash
144
+ id = session.id || request.session_options[:id]
145
+
146
+ if id.respond_to?(:cookie_value)
147
+ id.cookie_value
148
+ elsif id.is_a?(Rack::Session::SessionId)
149
+ id.public_id
150
+ else
151
+ id.to_s
152
+ end
153
+ end
154
+
155
+ def params_hash
156
+ request.params.except(:controller, :action, :id)
157
+ end
158
+
159
+ #use both @current_user and current_user helper
160
+ def user_id
161
+ user_id = @current_user ? @current_user.id : nil rescue nil
162
+ user_id = current_user ? current_user.id : nil rescue nil if user_id.blank?
163
+ user_id
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,2 @@
1
+ class Impression
2
+ end