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
@@ -0,0 +1,62 @@
1
+ module Impressionist
2
+ module Impressionable
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ attr_accessor :impressionist_cache_options
7
+
8
+ DEFAULT_CACHE ||= {
9
+ :counter_cache => false,
10
+ :column_name => :impressions_count,
11
+ :unique => :all
12
+ }
13
+
14
+ def impressionist_counter_cache_options
15
+ @impressionist_cache_options ||= {}
16
+ @impressionist_cache_options.reverse_merge!(DEFAULT_CACHE)
17
+ end
18
+
19
+ # asks impressionable entity whether or not it is counter_caching
20
+ def impressionist_counter_caching?
21
+ impressionist_counter_cache_options[:counter_cache]
22
+ end
23
+
24
+ def counter_caching?
25
+ ::ActiveSupport::Deprecation.warn("#counter_caching? is deprecated; please use #impressionist_counter_caching? instead")
26
+ impressionist_counter_caching?
27
+ end
28
+
29
+ end # end of ClassMethods
30
+
31
+ def impressionist_count(options={})
32
+ # Uses these options as defaults unless overridden in options hash
33
+ options.reverse_merge!(:filter => :request_hash, :start_date => nil, :end_date => Time.now)
34
+
35
+ # If a start_date is provided, finds impressions between then and the end_date. Otherwise returns all impressions
36
+ imps = options[:start_date].blank? ? impressions : impressions.where("created_at >= ? and created_at <= ?", options[:start_date], options[:end_date])
37
+
38
+ if options[:message]
39
+ imps = imps.where("impressions.message = ?", options[:message])
40
+ end
41
+
42
+ # Count all distinct impressions unless the :all filter is provided.
43
+ distinct = options[:filter] != :all
44
+ if Rails::VERSION::MAJOR >= 4
45
+ distinct ? imps.select(options[:filter]).distinct.count : imps.count
46
+ else
47
+ distinct ? imps.count(options[:filter], :distinct => true) : imps.count
48
+ end
49
+ end
50
+
51
+ def update_impressionist_counter_cache
52
+ slave = Impressionist::UpdateCounters.new(self)
53
+ slave.update
54
+ end
55
+
56
+ def impressionable?
57
+ true
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
4
+ require 'impressionist/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'impressionist-cody'
8
+ s.version = Impressionist::VERSION.dup
9
+ s.platform = Gem::Platform::RUBY
10
+ s.licenses = ['MIT']
11
+ s.summary = 'Easy way to log impressions'
12
+ s.email = 'john.mcaliley@gmail.com'
13
+ s.homepage = 'http://github.com/charlotte-ruby/impressionist'
14
+ s.description = 'Log impressions from controller actions or from a model'
15
+ s.authors = ['johnmcaliley']
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- tests/**/*`.split("\n")
19
+ s.require_path = 'lib'
20
+
21
+ s.add_dependency "friendly_id"
22
+ s.add_dependency 'nokogiri', RUBY_VERSION < '2.1.0' ? '~> 1.6.0' : '~> 1'
23
+ s.add_dependency 'rails', '>= 3.2.15'
24
+ s.add_dependency 'zeitwerk'
25
+
26
+ s.add_development_dependency 'bundler', '~> 2.0'
27
+ s.add_development_dependency 'capybara'
28
+ s.add_development_dependency 'rspec-rails'
29
+ s.add_development_dependency 'sqlite3', '~> 1.4'
30
+ end
@@ -0,0 +1,22 @@
1
+ module ActiveRecord
2
+ module Generators
3
+ class ImpressionistGenerator < Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+ source_root File.join(File.dirname(__FILE__), 'templates')
6
+
7
+ # FIX, why is this implementing rails behaviour?
8
+ def self.next_migration_number(dirname)
9
+ sleep 1
10
+ if ActiveRecord::Base.timestamped_migrations
11
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
12
+ else
13
+ "%.3d" % (current_migration_number(dirname) + 1)
14
+ end
15
+ end
16
+
17
+ def create_migration_file
18
+ migration_template 'create_impressions_table.rb.erb', 'db/migrate/create_impressions_table.rb'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ class CreateImpressionsTable < ActiveRecord::Migration<%= Rails::VERSION::MAJOR >= 5 ? "[#{Rails.version.to_f}]" : "" %>
2
+ def self.up
3
+ create_table :impressions, :force => true do |t|
4
+ t.string :impressionable_type
5
+ t.integer :impressionable_id
6
+ t.integer :user_id
7
+ t.string :controller_name
8
+ t.string :action_name
9
+ t.string :view_name
10
+ t.string :request_hash
11
+ t.string :ip_address
12
+ t.string :session_hash
13
+ t.text :message
14
+ t.text :referrer
15
+ t.text :params
16
+ t.timestamps
17
+ end
18
+ add_index :impressions, [:impressionable_type, :message, :impressionable_id], :name => "impressionable_type_message_index", :unique => false, :length => {:message => 255 }
19
+ add_index :impressions, [:impressionable_type, :impressionable_id, :request_hash], :name => "poly_request_index", :unique => false
20
+ add_index :impressions, [:impressionable_type, :impressionable_id, :ip_address], :name => "poly_ip_index", :unique => false
21
+ add_index :impressions, [:impressionable_type, :impressionable_id, :session_hash], :name => "poly_session_index", :unique => false
22
+ add_index :impressions, [:controller_name,:action_name,:request_hash], :name => "controlleraction_request_index", :unique => false
23
+ add_index :impressions, [:controller_name,:action_name,:ip_address], :name => "controlleraction_ip_index", :unique => false
24
+ add_index :impressions, [:controller_name,:action_name,:session_hash], :name => "controlleraction_session_index", :unique => false
25
+ add_index :impressions, [:impressionable_type, :impressionable_id, :params], :name => "poly_params_request_index", :unique => false, :length => {:params => 255 }
26
+ add_index :impressions, :user_id
27
+ end
28
+
29
+ def self.down
30
+ drop_table :impressions
31
+ end
32
+ end
@@ -0,0 +1,13 @@
1
+ module Impressionist
2
+ module Generators
3
+ class ImpressionistGenerator < Rails::Generators::Base
4
+ hook_for :orm
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ def copy_config_file
8
+ template 'impression.rb.erb', 'config/initializers/impression.rb'
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module MongoMapper
2
+ module Generators
3
+ class ImpressionistGenerator < Rails::Generators::Base
4
+ # Empty for now, need it for generating the config file without
5
+ # triggering other ORM's generators.
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Mongoid
2
+ module Generators
3
+ class ImpressionistGenerator < Rails::Generators::Base
4
+ # Empty for now, need it for generating the config file without
5
+ # triggering other ORM's generators.
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # Use this hook to configure impressionist parameters
2
+ #Impressionist.setup do |config|
3
+ # Define ORM. Could be :active_record (default), :mongo_mapper or :mongoid
4
+ # config.orm = :active_record
5
+ #end
6
+
7
+ <% orm = options.orm.match(/mongoid|active_record|mongomapper/) %>
8
+ <%= "Impressionist.orm = :#{options.orm}" if String === options.orm %>
@@ -0,0 +1,21 @@
1
+ require 'timeout'
2
+ require 'net/http'
3
+ require 'nokogiri'
4
+
5
+ module Impressionist
6
+ module Bots
7
+ LIST_URL = "http://www.user-agents.org/allagents.xml"
8
+ def self.consume
9
+ Timeout.timeout(4) do
10
+ response = Net::HTTP.get(URI.parse(LIST_URL))
11
+ doc = Nokogiri::XML(response)
12
+ list = []
13
+ doc.xpath('//user-agent').each do |agent|
14
+ type = agent.xpath("Type").text
15
+ list << agent.xpath("String").text.gsub("&lt;","<") if ["R","S"].include?(type) #gsub hack for badly formatted data
16
+ end
17
+ list
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ ImpressionistController::InstanceMethods.send(:define_method, :direct_create_statement) do |query_params={}|
2
+ # creates a statment hash that contains default values for creating an impression.
3
+ # if :impressionable_id is a valid ObjectId then convert it into one
4
+ base = (defined? Moped) ? Moped::BSON : BSON
5
+ query_params.reverse_merge!(
6
+ :impressionable_type => controller_path.singularize.camelize,
7
+ :impressionable_id=> !base::ObjectId.legal?(params[:id]) ? params[:id] : base::ObjectId.from_string(params[:id])
8
+ )
9
+ associative_create_statement(query_params)
10
+ end
@@ -0,0 +1,76 @@
1
+ module Impressionist
2
+ module CounterCache
3
+
4
+ attr_reader :impressionable_class, :entity
5
+
6
+ private
7
+
8
+ # A valid impression must
9
+ # have a valid impressionable class
10
+ # be counter_caching
11
+ # have a record saved in the db
12
+ # then it should give it a try
13
+ def impressionable_counter_cache_updatable?
14
+ updatable? && impressionable_try
15
+ end
16
+
17
+ def updatable?
18
+ valid_impressionable_class? && impressionable_find
19
+ end
20
+
21
+ def valid_impressionable_class?
22
+ set_impressionable_class && counter_caching?
23
+ end
24
+
25
+ def set_impressionable_class
26
+ klass = self.impressionable_type || false
27
+ @impressionable_class = klass.
28
+ to_s.safe_constantize || false
29
+ end
30
+
31
+ def impressionist_log(str, mode=:error)
32
+ Rails.logger.send(mode.to_s, str)
33
+ end
34
+
35
+ # receives an entity(instance of a Model) and then tries to update
36
+ # counter_cache column
37
+ # entity is a impressionable instance model
38
+ def impressionable_try
39
+ entity.try(:update_impressionist_counter_cache)
40
+ end
41
+
42
+ def impressionable_find
43
+ exeception_rescuer {
44
+ @entity = impressionable_class.find(self.impressionable_id)
45
+ }
46
+ @entity
47
+
48
+ end
49
+
50
+ def counter_caching?
51
+ if impressionable_class.respond_to?(:impressionist_counter_caching?)
52
+ impressionable_class.impressionist_counter_caching?
53
+ else
54
+ false
55
+ end
56
+ end
57
+
58
+
59
+ # Returns false, as it is only handling one exeception
60
+ # It would make updatable to fail thereafter it would not try
61
+ # to update cache_counter
62
+ def exeception_rescuer
63
+ begin
64
+ yield
65
+ rescue ActiveRecord::RecordNotFound
66
+ exeception_to_log
67
+ false
68
+ end
69
+ end
70
+
71
+ def exeception_to_log
72
+ impressionist_log("Couldn't find Widget with id=#{self.impressionable_id}")
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,45 @@
1
+ module Impressionist
2
+ class Engine < ::Rails::Engine
3
+ attr_accessor :orm
4
+
5
+ initializer 'impressionist.model' do |app|
6
+ @orm = Impressionist.orm
7
+ include_orm
8
+ end
9
+
10
+
11
+ initializer 'impressionist.controller' do
12
+ require "impressionist/controllers/mongoid/impressionist_controller" if orm == :mongoid.to_s
13
+
14
+ ActiveSupport.on_load(:action_controller) do
15
+ include ImpressionistController::InstanceMethods
16
+ extend ImpressionistController::ClassMethods
17
+ end
18
+ end
19
+
20
+
21
+ private
22
+
23
+ def include_orm
24
+ require "#{root}/app/models/impressionist/impressionable.rb"
25
+ require "impressionist/models/#{orm}/impression.rb"
26
+ require "impressionist/models/#{orm}/impressionist/impressionable.rb"
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ require 'zeitwerk'
34
+
35
+ loader = Zeitwerk::Loader.new
36
+ impression = Impressionist::Engine.root
37
+ impression_lib = impression.join('lib')
38
+ impression_con = impression.join('app', 'controllers')
39
+ impression_mod = impression.join('app', 'models')
40
+
41
+
42
+ loader.push_dir(impression_lib, namespace: Impressionist)
43
+ loader.push_dir(impression_con, namespace: Impressionist)
44
+ loader.push_dir(impression_mod, namespace: Impressionist)
45
+ loader.setup
@@ -0,0 +1,23 @@
1
+ module Impressionist
2
+ module IsImpressionable
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def is_impressionable(options={})
7
+ define_association
8
+ @impressionist_cache_options = options
9
+
10
+ true
11
+ end
12
+
13
+ private
14
+
15
+ def define_association
16
+ has_many(:impressions,
17
+ :as => :impressionable,
18
+ :dependent => :delete_all)
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ require 'impressionist/setup_association'
2
+
3
+ require 'impressionist/counter_cache'
4
+
5
+ require 'impressionist/update_counters'
6
+
7
+ require 'impressionist/rails_toggle'
8
+
9
+ require 'impressionist/is_impressionable'
10
+
11
+ require 'impressionist/engine'
@@ -0,0 +1,14 @@
1
+ # Responsability
2
+ # * logs an error if imps_id and imps_type can not be found
3
+ # * asks updatable? whether it may or may not be updated
4
+
5
+ class Impression < ActiveRecord::Base
6
+
7
+ include Impressionist::CounterCache
8
+
9
+ # sets belongs_to and attr_accessible depending on Rails version
10
+ Impressionist::SetupAssociation.new(self).set
11
+
12
+ store :params
13
+ after_save :impressionable_counter_cache_updatable?
14
+ end
@@ -0,0 +1,12 @@
1
+ module Impressionist
2
+
3
+ module Impressionable
4
+
5
+ # extends AS::Concern
6
+ include Impressionist::IsImpressionable
7
+ end
8
+
9
+ end
10
+
11
+ ActiveRecord::Base.
12
+ send(:include, Impressionist::Impressionable)
@@ -0,0 +1,18 @@
1
+ class Impression
2
+ include MongoMapper::Document
3
+
4
+ key :impressionable_type, String
5
+ key :impressionable_id, String
6
+ key :user_id, String
7
+ key :controller_name, String
8
+ key :action_name, String
9
+ key :view_name, String
10
+ key :request_hash, String
11
+ key :ip_address, String
12
+ key :session_hash, String
13
+ key :message, String
14
+ key :referrer, String
15
+ timestamps!
16
+
17
+ belongs_to :impressionable, :polymorphic=>true
18
+ end
@@ -0,0 +1,21 @@
1
+ MongoMapper::Document.plugin Impressionist::Impressionable
2
+
3
+ module Impressionist
4
+ module Impressionable
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ def is_impressionable(options={})
10
+ many(:impressions,
11
+ :as => :impressionable,
12
+ :dependent => :delete_all)
13
+
14
+ @impressionist_cache_options = options
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,26 @@
1
+ ##
2
+ # see active_record/impression.rb
3
+ # same doc applies to here
4
+ class Impression
5
+ include Mongoid::Document
6
+ include Mongoid::Timestamps
7
+
8
+ include Impressionist::CounterCache
9
+ Impressionist::SetupAssociation.new(self).set
10
+
11
+ field :impressionable_id, type: BSON::ObjectId
12
+ field :impressionable_type
13
+ field :user_id
14
+ field :controller_name
15
+ field :action_name
16
+ field :view_name
17
+ field :request_hash
18
+ field :ip_address
19
+ field :session_hash
20
+ field :message
21
+ field :referrer
22
+ field :params
23
+
24
+ after_save :impressionable_counter_cache_updatable?
25
+
26
+ end
@@ -0,0 +1,28 @@
1
+ module Impressionist
2
+ module Impressionable
3
+
4
+ # extends AS::Concern
5
+ include Impressionist::IsImpressionable
6
+
7
+ # Overides impressionist_count in order to provide mongoid compability
8
+ def impressionist_count(options={})
9
+
10
+ # Uses these options as defaults unless overridden in options hash
11
+ options.reverse_merge!(:filter => :request_hash, :start_date => nil, :end_date => Time.now)
12
+
13
+ # If a start_date is provided, finds impressions between then and the end_date.
14
+ # Otherwise returns all impressions
15
+ imps = options[:start_date].blank? ? impressions :
16
+ impressions.between(created_at: options[:start_date]..options[:end_date])
17
+
18
+
19
+ # Count all distinct impressions unless the :all filter is provided
20
+ distinct = options[:filter] != :all
21
+ distinct ? imps.where(options[:filter].ne => nil).distinct(options[:filter]).count : imps.count
22
+ end
23
+
24
+ end
25
+ end
26
+
27
+ Mongoid::Document.
28
+ send(:include, Impressionist::Impressionable)
@@ -0,0 +1,26 @@
1
+ module Impressionist
2
+ # Responsibility
3
+ # Toggles between rails > 3.1 < 4
4
+ # In order to make attr_accessible available in a rails app < 4
5
+
6
+ class RailsToggle
7
+ # decides where or not to include attr_accessible
8
+ def should_include?
9
+ supported_by_rails? && (not using_strong_parameters?)
10
+ end
11
+
12
+ private
13
+
14
+ def using_strong_parameters?
15
+ defined?(StrongParameters)
16
+ end
17
+
18
+ # returns false if rails >= 4
19
+ # true if rails < 4
20
+ def supported_by_rails?
21
+ ::Rails::VERSION::MAJOR.to_i < 4
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,53 @@
1
+ module Impressionist
2
+ # Impressionist::SetupAssociation.new(entity).set
3
+ class SetupAssociation
4
+ def initialize(receiver)
5
+ @receiver = receiver
6
+ end
7
+
8
+ # True or False
9
+ # Note toggle returns false if rails >= 4
10
+ def include_attr_acc?
11
+ toggle && make_accessible
12
+ end
13
+
14
+ def define_belongs_to
15
+ if ::Rails::VERSION::MAJOR.to_i >= 5
16
+ receiver.belongs_to(:impressionable, :polymorphic => true, :optional => true)
17
+ else
18
+ receiver.belongs_to(:impressionable, :polymorphic => true)
19
+ end
20
+ end
21
+
22
+ def set
23
+ define_belongs_to
24
+ include_attr_acc?
25
+ end
26
+
27
+ private
28
+ attr_reader :receiver, :toggle
29
+
30
+ def make_accessible
31
+ receiver.
32
+ attr_accessible(:impressionable_type,
33
+ :impressionable_id,
34
+ :controller_name,
35
+ :request_hash,
36
+ :session_hash,
37
+ :action_name,
38
+ :ip_address,
39
+ :view_name,
40
+ :referrer,
41
+ :message,
42
+ :user_id,
43
+ :params)
44
+ end
45
+
46
+ def toggle
47
+ t = RailsToggle.new
48
+ t.should_include?
49
+ end
50
+ end
51
+ end
52
+
53
+
@@ -0,0 +1,77 @@
1
+ # Note
2
+ # If impressionist_counter_cache_options[:counter_cache] is false(default)
3
+ # it won't even run this class
4
+ module Impressionist
5
+
6
+ class UpdateCounters
7
+ attr_reader :receiver, :klass
8
+
9
+ def initialize(receiver)
10
+ @receiver = receiver
11
+ @klass = receiver.class
12
+ end
13
+
14
+ def update
15
+ klass.
16
+ update_counters(id, column_name => result)
17
+ end
18
+
19
+ private
20
+
21
+ def result
22
+ impressions_total - impressions_cached
23
+ end
24
+
25
+ # Count impressions based on unique_filter
26
+ # default is :ip_address when unique: true
27
+ def impressions_total
28
+ receiver.impressionist_count filter
29
+ end
30
+
31
+ # Fetch impressions from a receiver's column
32
+ def impressions_cached
33
+ receiver.send(column_name) || 0
34
+ end
35
+
36
+ def filter
37
+ {:filter => unique_filter}
38
+ end
39
+
40
+ # :filter gets assigned to :ip_address as default
41
+ # One could do
42
+ # is_impressionable :counter_cache => true,
43
+ # :unique => :any_other_filter
44
+ def unique_filter
45
+ # Support `is_impressionable :counter_cache => true, :unique => true`
46
+ # defaulting to `:ip_address` for counting unique impressions.
47
+ return :ip_address if unique == true
48
+
49
+ # Should a user try `is_impressionable :counter_cache => true, :unique => false`
50
+ # then support that as well
51
+ return :all if unique == false
52
+
53
+ # Otherwise set the filter to either what the user supplied as the `unique` option
54
+ # or the default (`:all`)
55
+ unique
56
+ end
57
+
58
+ def unique
59
+ cache_options[:unique]
60
+ end
61
+
62
+ def column_name
63
+ cache_options[:column_name].to_s
64
+ end
65
+
66
+ def cache_options
67
+ klass.
68
+ impressionist_counter_cache_options
69
+ end
70
+
71
+ def id
72
+ receiver.id
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,3 @@
1
+ module Impressionist
2
+ VERSION = "2.0.0"
3
+ end