ahoy-views 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7833368548e41179bc7ae7697fde7102958f3dfc65f6cd76b1cafeb485533626
4
+ data.tar.gz: 1c7bc67cb59b0dea5ffd44f3c6255e369ae4fbbafe0160e19297614c361df754
5
+ SHA512:
6
+ metadata.gz: abf402fecadcdb107dd623087b64649c43e7805c48fea51b3c2e86a70194ef17510eb9f529b47a4bbc142764749e9eb2ced9b785ec52acc3be33af06fe5f112d
7
+ data.tar.gz: 984ec5a5004c3a50fb2be4a25c35ce28824b1fec28553ff182720953dbeba262216584f328ccde01e74e9c5f90b61ddc3a4d4c209075090c4db61eea12906d96
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ### master
4
+
5
+ * nothing yet
6
+
7
+ ### 1.0.0 - 2018/01/13
8
+
9
+ * initial release
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Jonas Hübotter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,209 @@
1
+ # Ahoy Views
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/ahoy-views.svg)](https://badge.fury.io/rb/ahoy-views) <img src="https://travis-ci.org/jonhue/ahoy-views.svg?branch=master" />
4
+
5
+ Track views of ActiveRecord objects in Rails. Ahoy Views depends on [Ahoy](https://github.com/ankane/ahoy).
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ * [Installation](#installation)
12
+ * [Usage](#usage)
13
+ * [Tracking](#tracking)
14
+ * [Types](#types)
15
+ * [`ahoy_viewable`](#ahoy_viewable)
16
+ * [`ahoy_viewer`](#ahoy_viewer)
17
+ * [To Do](#to-do)
18
+ * [Contributing](#contributing)
19
+ * [Contributors](#contributors)
20
+ * [Semantic versioning](#semantic-versioning)
21
+ * [License](#license)
22
+
23
+ ---
24
+
25
+ ## Installation
26
+
27
+ **Note:** Before installing Ahoy Views make sure to setup the original [Ahoy](https://github.com/ankane/ahoy) gem.
28
+
29
+ Ahoy Views works with Rails 5 onwards. You can add it to your `Gemfile` with:
30
+
31
+ ```ruby
32
+ gem 'ahoy-views'
33
+ ```
34
+
35
+ And then execute:
36
+
37
+ $ bundle
38
+
39
+ Or install it yourself as:
40
+
41
+ $ gem install ahoy_views
42
+
43
+ If you always want to be up to date fetch the latest from GitHub in your `Gemfile`:
44
+
45
+ ```ruby
46
+ gem 'ahoy-views', github: 'jonhue/ahoy-views'
47
+ ```
48
+
49
+ Now run the generator:
50
+
51
+ $ rails g ahoy_views
52
+
53
+ Lastly make sure to call `ahoy_views` from your `Ahoy::Event` class:
54
+
55
+ ```ruby
56
+ module Ahoy
57
+ class Event < ApplicationRecord
58
+ ahoy_views
59
+ end
60
+ end
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Usage
66
+
67
+ ### Tracking
68
+
69
+ You can track views for ActiveRecord objects from your controllers:
70
+
71
+ ```ruby
72
+ class ArticleController < ApplicationController
73
+
74
+ def index
75
+ @articles = Article.all
76
+ ahoy_view @articles
77
+ end
78
+
79
+ def show
80
+ @article = Article.find params[:id]
81
+ ahoy_view @article
82
+ end
83
+
84
+ end
85
+ ```
86
+
87
+ **Note:** This will create an `Ahoy::Event` object for every record passed.
88
+
89
+ The `current_visit` object, if present, will be automatically associated with every visit.
90
+
91
+ You are also able to associate other records with views. [Learn more](#ahoy_viewer).
92
+
93
+ #### Types
94
+
95
+ You can pass an array of `types` to `ahoy_view`. Types allow you to track multiple types of visits. The `:types` option defaults to `[:visit]`.
96
+
97
+ ```ruby
98
+ ahoy_view @article, types: [:view, :visitor, :returnee, :unique_visitor, :unique_returnee]
99
+ ```
100
+
101
+ Here is a list of available types:
102
+
103
+ * `:visit` stores every call to `ahoy_view` for an object.
104
+
105
+ * `:visitor` stores only one call per visit to `ahoy_view`.
106
+
107
+ * `:returnee` ...
108
+
109
+ * `:unique_visitor` ...
110
+
111
+ * `:unique_returnee` ...
112
+
113
+ ### `ahoy_viewable`
114
+
115
+ Add `ahoy_viewable` to an ActiveRecord class.
116
+
117
+ ```ruby
118
+ class Article < ApplicationRecord
119
+ ahoy_viewable
120
+ end
121
+
122
+ a = Article.first
123
+
124
+ # All belonging Ahoy::Event objects that are a view
125
+ a.ahoy_views
126
+
127
+ # All viewer records that have a view object
128
+ a.ahoy_viewers
129
+
130
+ # Scope to order Article records by views
131
+ Article.trending
132
+
133
+ # Whether or not a is one of the 5 "most trending" articles
134
+ a.trending? 5
135
+ ```
136
+
137
+ ### `ahoy_viewer`
138
+
139
+ Add `ahoy_viewer` to an ActiveRecord class.
140
+
141
+ ```ruby
142
+ class User < ApplicationRecord
143
+ ahoy_viewer
144
+ end
145
+
146
+ u = User.first
147
+
148
+ # All belonging Ahoy::Event objects that are a view
149
+ u.ahoy_visits
150
+
151
+ # All records that this user has taken a look at
152
+ u.ahoy_viewed
153
+ ```
154
+
155
+ Here is how to associate a viewer with a view:
156
+
157
+ ```ruby
158
+ ahoy_view @article, viewer: current_user
159
+ ```
160
+
161
+ ---
162
+
163
+ ## To Do
164
+
165
+ [Here](https://github.com/jonhue/ahoy-views/projects/1) is the full list of current projects.
166
+
167
+ To propose your ideas, initiate the discussion by adding a [new issue](https://github.com/jonhue/ahoy-views/issues/new).
168
+
169
+ ---
170
+
171
+ ## Contributing
172
+
173
+ We hope that you will consider contributing to Ahoy Views. Please read this short overview for some information about how to get started:
174
+
175
+ [Learn more about contributing to this repository](CONTRIBUTING.md), [Code of Conduct](CODE_OF_CONDUCT.md)
176
+
177
+ ### Contributors
178
+
179
+ Give the people some :heart: who are working on this project. See them all at:
180
+
181
+ https://github.com/jonhue/ahoy-views/graphs/contributors
182
+
183
+ ### Semantic Versioning
184
+
185
+ Ahoy Views follows Semantic Versioning 2.0 as defined at http://semver.org.
186
+
187
+ ## License
188
+
189
+ MIT License
190
+
191
+ Copyright (c) 2018 Jonas Hübotter
192
+
193
+ Permission is hereby granted, free of charge, to any person obtaining a copy
194
+ of this software and associated documentation files (the "Software"), to deal
195
+ in the Software without restriction, including without limitation the rights
196
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
197
+ copies of the Software, and to permit persons to whom the Software is
198
+ furnished to do so, subject to the following conditions:
199
+
200
+ The above copyright notice and this permission notice shall be included in all
201
+ copies or substantial portions of the Software.
202
+
203
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
204
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
205
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
206
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
207
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
208
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
209
+ SOFTWARE.
@@ -0,0 +1,14 @@
1
+ require 'ahoy/views/version'
2
+
3
+ module Ahoy
4
+ module Views
5
+
6
+ autoload :View, 'ahoy/views/view'
7
+ autoload :Viewable, 'ahoy/views/viewable'
8
+ autoload :Viewer, 'ahoy/views/viewer'
9
+ autoload :Views, 'ahoy/views/views'
10
+
11
+ require 'ahoy/views/railtie'
12
+
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails/railtie'
2
+
3
+ module Ahoy
4
+ module Views
5
+ class Railtie < Rails::Railtie
6
+
7
+ initializer 'ahoy-views.active_record' do
8
+ ActiveSupport.on_load :active_record do
9
+ include Ahoy::Views::Views
10
+ include Ahoy::Views::Viewer
11
+ include Ahoy::Views::Viewable
12
+ end
13
+ end
14
+
15
+ initializer 'ahoy-views.action_controller' do
16
+ ActiveSupport.on_load :action_controller do
17
+ include Ahoy::Views::View
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ module Ahoy
2
+ module Views
3
+
4
+ VERSION = '1.0.0'
5
+
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ module Ahoy
2
+ module Views
3
+ module View
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ def ahoy_view objects, options = {}
8
+ defaults = {
9
+ types: [:view],
10
+ viewer: nil
11
+ }
12
+ options = defaults.merge! options
13
+
14
+ if current_visit
15
+ if objects.kind_of? Array
16
+ objects.each do |object|
17
+ track_ahoy_view object, options[:types], options[:viewer]
18
+ end
19
+ else
20
+ track_ahoy_view objects, options[:types], options[:viewer]
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def track_ahoy_view object, types, viewer
28
+ types.each do |name|
29
+ ahoy.track name, visited: object, visitor: viewer, visit: current_visit
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ module Ahoy
2
+ module Views
3
+ module Viewable
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ def ahoy_viewable
10
+ has_many :ahoy_views, as: :visited, class_name: 'Ahoy::Event'
11
+ has_many :ahoy_viewers, through: :ahoy_views, source: :visitor
12
+
13
+ scope :trending, -> { left_joins(:views).group(:id).order('count(views.id) desc') }
14
+
15
+ include Ahoy::Views::Viewable::InstanceMethods
16
+ end
17
+
18
+ end
19
+
20
+ module InstanceMethods
21
+
22
+ def trending? limit
23
+ self.class.trending.limit(limit).include? self
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ module Ahoy
2
+ module Views
3
+ module Viewer
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ def ahoy_viewer
10
+ has_many :ahoy_visits, as: :visitor, class_name: 'Ahoy::Event'
11
+ has_many :ahoy_viewed, through: :ahoy_visits, source: :visited
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,50 @@
1
+ module Ahoy
2
+ module Views
3
+ module Views
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ def ahoy_views
10
+ before_create :process_view
11
+
12
+ belongs_to :visitor, polymorphic: true, optional: true
13
+ belongs_to :visited, polymorphic: true, optional: true
14
+
15
+ scope :appearances, -> { where name: 'appearance' }
16
+ scope :views, -> { where name: 'view' }
17
+ scope :visitors, -> { where name: 'visitor' }
18
+ scope :returnees, -> { where name: 'returnee' }
19
+ scope :visited_in_session, -> (visit) { where visit_id: visit.id }
20
+ scope :visited, -> (visitor) { where visitor_id: visitor.id, visitor_type: visitor.class.name }
21
+
22
+ include Ahoy::Views::Views::InstanceMethods
23
+ end
24
+
25
+ end
26
+
27
+ module InstanceMethods
28
+
29
+ private
30
+
31
+ def process_view
32
+ if self.visited && self.name
33
+ case self.name
34
+ when 'visitor'
35
+ return false if self.class.visitors.visited_in_session(self.visit).where(visited_id: visited.id, visited_type: visited.class.name).any?
36
+ when 'returnee'
37
+ return false if self.class.returnees.visited_in_session(self.visit).where(visited_id: visited.id, visited_type: visited.class.name).any? && !self.class.visited(self.visitor).where(visited_id: visited.id, visited_type: visited.class.name).any?
38
+ when 'unique_visitor'
39
+ return false if self.class.visitors.visited(self.visitor).where(visited_id: visited.id, visited_type: visited.class.name).any?
40
+ when 'unique_returnee'
41
+ return false if self.class.returnees.visited(self.visitor).where(visited_id: visited.id, visited_type: visited.class.name).any? && !self.class.visited(self.visitor).where(visited_id: visited.id, visited_type: visited.class.name).any?
42
+ end
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,35 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class AhoyViewsGenerator < Rails::Generators::Base
5
+
6
+ include Rails::Generators::Migration
7
+
8
+ source_root File.join File.dirname(__FILE__), 'templates'
9
+ desc 'Install ahoy-views'
10
+
11
+ def self.next_migration_number dirname
12
+ if ActiveRecord::Base.timestamped_migrations
13
+ Time.now.utc.strftime '%Y%m%d%H%M%S'
14
+ else
15
+ "%.3d" % (current_migration_number(dirname) + 1)
16
+ end
17
+ end
18
+
19
+ def create_migration_file
20
+ migration_template 'migration.rb.erb', 'db/migrate/ahoy_views_migration.rb', migration_version: migration_version
21
+ end
22
+
23
+ def show_readme
24
+ readme 'README.md'
25
+ end
26
+
27
+ private
28
+
29
+ def migration_version
30
+ if Rails.version >= '5.0.0'
31
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1 @@
1
+ Now run `rails db:migrate` to add ahoy-views to your database.
@@ -0,0 +1,8 @@
1
+ class AhoyViewsMigration < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ add_column :ahoy_events, :visitor_id, :bigint, index: true
4
+ add_column :ahoy_events, :visitor_type, :string, index: true
5
+ add_column :ahoy_events, :visited_id, :bigint, index: true
6
+ add_column :ahoy_events, :visited_type, :string, index: true
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ahoy-views
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonas Hübotter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-01-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: actionpack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ahoy_matey
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.6'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.7'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.52'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.52'
111
+ description: Track views of ActiveRecord objects in Rails.
112
+ email: me@jonhue.me
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - CHANGELOG.md
118
+ - LICENSE
119
+ - README.md
120
+ - lib/ahoy-views.rb
121
+ - lib/ahoy/views/railtie.rb
122
+ - lib/ahoy/views/version.rb
123
+ - lib/ahoy/views/view.rb
124
+ - lib/ahoy/views/viewable.rb
125
+ - lib/ahoy/views/viewer.rb
126
+ - lib/ahoy/views/views.rb
127
+ - lib/generators/ahoy_views_generator.rb
128
+ - lib/generators/templates/README.md
129
+ - lib/generators/templates/migration.rb.erb
130
+ homepage: https://github.com/jonhue/ahoy-views
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '2.3'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.7.4
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Track views of ActiveRecord objects in Rails
154
+ test_files: []