From 2d69ac3ab02a31bd69c0d08ebdc647fc3e6cd62c Mon Sep 17 00:00:00 2001 From: Dean Lofts Date: Sun, 18 Aug 2024 22:39:35 +1000 Subject: [PATCH 1/2] implement tracking and analytics --- app/controllers/achievements_controller.rb | 17 +++- app/controllers/links_controller.rb | 16 +++- app/middleware/page_view_tracker.rb | 35 +++++++++ app/models/achievement.rb | 2 + app/models/achievement_view.rb | 4 + app/models/link.rb | 2 + app/models/link_click.rb | 4 + app/models/page_view.rb | 3 + app/models/user.rb | 4 + app/views/links/user_links.html.erb | 6 +- config/application.rb | 6 +- config/routes.rb | 6 ++ .../20240818111049_create_page_views.rb | 13 ++++ .../20240818111055_create_link_clicks.rb | 13 ++++ ...20240818111101_create_achievement_views.rb | 13 ++++ ...ess_and_session_id_to_achievement_views.rb | 6 ++ ...p_address_and_session_id_to_link_clicks.rb | 6 ++ ...ip_address_and_session_id_to_page_views.rb | 6 ++ db/schema.rb | 78 ++++++++++++++++++- spec/models/achievement_view_spec.rb | 5 ++ spec/models/link_click_spec.rb | 5 ++ spec/models/page_view_spec.rb | 5 ++ 22 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 app/middleware/page_view_tracker.rb create mode 100644 app/models/achievement_view.rb create mode 100644 app/models/link_click.rb create mode 100644 app/models/page_view.rb create mode 100644 db/migrate/20240818111049_create_page_views.rb create mode 100644 db/migrate/20240818111055_create_link_clicks.rb create mode 100644 db/migrate/20240818111101_create_achievement_views.rb create mode 100644 db/migrate/20240818123616_add_ip_address_and_session_id_to_achievement_views.rb create mode 100644 db/migrate/20240818123618_add_ip_address_and_session_id_to_link_clicks.rb create mode 100644 db/migrate/20240818123619_add_ip_address_and_session_id_to_page_views.rb create mode 100644 spec/models/achievement_view_spec.rb create mode 100644 spec/models/link_click_spec.rb create mode 100644 spec/models/page_view_spec.rb diff --git a/app/controllers/achievements_controller.rb b/app/controllers/achievements_controller.rb index 35e1a85..f5ba036 100644 --- a/app/controllers/achievements_controller.rb +++ b/app/controllers/achievements_controller.rb @@ -7,6 +7,21 @@ def index def show @achievement = Achievement.find(params[:id]) + AchievementView.create( + achievement: @achievement, + user: @achievement.user, + viewed_at: Time.current, + referrer: request.referrer, + browser: request.user_agent, + ip_address: request.ip, + session_id: request.session.id + ) + + if @achievement.url.present? + redirect_to @achievement.url, allow_other_host: true + else + render :show + end end def new @@ -46,4 +61,4 @@ def destroy def achievement_params params.require(:achievement).permit(:title, :date, :description, :icon, :url) end -end +end \ No newline at end of file diff --git a/app/controllers/links_controller.rb b/app/controllers/links_controller.rb index 863c8b1..170d915 100644 --- a/app/controllers/links_controller.rb +++ b/app/controllers/links_controller.rb @@ -49,9 +49,23 @@ def user_links @user.tags = JSON.parse(@user.tags) if @user.tags.is_a?(String) end + def track_click + @link = Link.find(params[:id]) + LinkClick.create( + link: @link, + user: @link.user, + clicked_at: Time.current, + referrer: request.referrer, + browser: request.user_agent, + ip_address: request.ip, + session_id: request.session.id + ) + redirect_to @link.url, allow_other_host: true + end + private def link_params params.require(:link).permit(:url, :title, :description, :position, :icon, :visible, :pinned) end -end +end \ No newline at end of file diff --git a/app/middleware/page_view_tracker.rb b/app/middleware/page_view_tracker.rb new file mode 100644 index 0000000..4ca38b1 --- /dev/null +++ b/app/middleware/page_view_tracker.rb @@ -0,0 +1,35 @@ +class PageViewTracker + def initialize(app) + @app = app + end + + def call(env) + request = ActionDispatch::Request.new(env) + status, headers, response = @app.call(env) + + if html_response?(headers) && !request.path.start_with?('/assets', '/rails/active_storage') + track_page_view(request) + end + + [status, headers, response] + end + + private + + def html_response?(headers) + headers['Content-Type']&.include?('text/html') + end + + def track_page_view(request) + user = User.find_by(username: request.path.split('/').last) + PageView.create( + user: user, + path: request.path, + referrer: request.referrer, + browser: request.user_agent, + visited_at: Time.current, + ip_address: request.ip, + session_id: request.session[:session_id] + ) if user + end +end \ No newline at end of file diff --git a/app/models/achievement.rb b/app/models/achievement.rb index cd70053..88e5a91 100644 --- a/app/models/achievement.rb +++ b/app/models/achievement.rb @@ -1,6 +1,8 @@ class Achievement < ApplicationRecord belongs_to :user + has_many :achievement_views + validates :title, presence: true validates :date, presence: true validates :description, presence: true diff --git a/app/models/achievement_view.rb b/app/models/achievement_view.rb new file mode 100644 index 0000000..4876677 --- /dev/null +++ b/app/models/achievement_view.rb @@ -0,0 +1,4 @@ +class AchievementView < ApplicationRecord + belongs_to :achievement + belongs_to :user +end diff --git a/app/models/link.rb b/app/models/link.rb index a3ffaca..5191d76 100644 --- a/app/models/link.rb +++ b/app/models/link.rb @@ -1,5 +1,7 @@ class Link < ApplicationRecord belongs_to :user + + has_many :link_clicks scope :visible, -> { where(visible: true) } scope :pinned, -> { where(pinned: true) } diff --git a/app/models/link_click.rb b/app/models/link_click.rb new file mode 100644 index 0000000..b53dadf --- /dev/null +++ b/app/models/link_click.rb @@ -0,0 +1,4 @@ +class LinkClick < ApplicationRecord + belongs_to :link + belongs_to :user +end diff --git a/app/models/page_view.rb b/app/models/page_view.rb new file mode 100644 index 0000000..34cc654 --- /dev/null +++ b/app/models/page_view.rb @@ -0,0 +1,3 @@ +class PageView < ApplicationRecord + belongs_to :user +end diff --git a/app/models/user.rb b/app/models/user.rb index 9b373e1..b896b01 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,6 +5,10 @@ class User < ApplicationRecord has_many :links, dependent: :destroy has_many :achievements, dependent: :destroy + has_many :page_views + has_many :link_clicks + has_many :achievement_views + validates :username, presence: true, uniqueness: true validates :full_name, presence: true diff --git a/app/views/links/user_links.html.erb b/app/views/links/user_links.html.erb index 4ab2761..1ebebca 100644 --- a/app/views/links/user_links.html.erb +++ b/app/views/links/user_links.html.erb @@ -26,7 +26,7 @@