Skip to content

Commit

Permalink
Merge pull request #10 from loftwah/dl/analytics
Browse files Browse the repository at this point in the history
Dl/analytics
  • Loading branch information
loftwah authored Aug 18, 2024
2 parents 219a954 + 50fd769 commit a8ef003
Show file tree
Hide file tree
Showing 23 changed files with 289 additions and 8 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,48 @@ Check out a live demo at [linkarooie.com](https://linkarooie.com).

5. Visit `http://localhost:3000` in your browser.

#### Analytics Temporary

I have added analytics but not a dashboard to view them yet. This is how it works so far.

- Open the Rails console `rails console`

```ruby
puts "Page Views for loftwah:"
user = User.find_by(username: 'loftwah')
puts user.page_views.count

puts "\nMost recent Page Views with new data:"
puts PageView.order(created_at: :desc).limit(5).map { |pv| "#{pv.path} - #{pv.created_at} - IP: #{pv.ip_address} - Session: #{pv.session_id}" }

puts "\nLink Clicks for loftwah's links:"
puts user.links.sum { |link| link.link_clicks.count }

puts "\nMost recent Link Clicks with new data:"
puts LinkClick.order(created_at: :desc).limit(5).map { |lc| "#{lc.link.title} - #{lc.created_at} - IP: #{lc.ip_address} - Session: #{lc.session_id}" }

puts "\nMost viewed pages:"
puts PageView.group(:path).order('count_id DESC').limit(5).count(:id)

puts "\nMost clicked links:"
puts LinkClick.joins(:link).group('links.title').order('count_id DESC').limit(5).count(:id)

puts "\nTotal tracking counts:"
puts "Page Views: #{PageView.count}"
puts "Link Clicks: #{LinkClick.count}"
puts "Achievement Views: #{AchievementView.count}"

puts "\nUnique IP addresses:"
puts "Page Views: #{PageView.distinct.count(:ip_address)}"
puts "Link Clicks: #{LinkClick.distinct.count(:ip_address)}"
puts "Achievement Views: #{AchievementView.distinct.count(:ip_address)}"

puts "\nUnique sessions:"
puts "Page Views: #{PageView.distinct.count(:session_id)}"
puts "Link Clicks: #{LinkClick.distinct.count(:session_id)}"
puts "Achievement Views: #{AchievementView.distinct.count(:session_id)}"
```

### Docker Deployment

1. Build and start the Docker containers:
Expand Down
17 changes: 16 additions & 1 deletion app/controllers/achievements_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -46,4 +61,4 @@ def destroy
def achievement_params
params.require(:achievement).permit(:title, :date, :description, :icon, :url)
end
end
end
16 changes: 15 additions & 1 deletion app/controllers/links_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
35 changes: 35 additions & 0 deletions app/middleware/page_view_tracker.rb
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions app/models/achievement.rb
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 4 additions & 0 deletions app/models/achievement_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class AchievementView < ApplicationRecord
belongs_to :achievement
belongs_to :user
end
2 changes: 2 additions & 0 deletions app/models/link.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
class Link < ApplicationRecord
belongs_to :user

has_many :link_clicks

scope :visible, -> { where(visible: true) }
scope :pinned, -> { where(pinned: true) }
Expand Down
4 changes: 4 additions & 0 deletions app/models/link_click.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class LinkClick < ApplicationRecord
belongs_to :link
belongs_to :user
end
3 changes: 3 additions & 0 deletions app/models/page_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class PageView < ApplicationRecord
belongs_to :user
end
4 changes: 4 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 3 additions & 3 deletions app/views/links/user_links.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<div class="pinned-links-section mt-4">
<div class="pinned-links flex flex-wrap justify-center">
<% @pinned_links.each do |link| %>
<%= link_to link.url, target: "_blank", class: 'icon-link bg-gray-800 p-3 m-1' do %>
<%= link_to track_click_link_path(link), target: "_blank", class: 'icon-link bg-gray-800 p-3 m-1' do %>
<i class="<%= link.icon %> text-lime-300"></i>
<% end %>
<% end %>
Expand All @@ -44,7 +44,7 @@
<% @links.where(pinned: false).each do |link| %>
<li class="bg-gray-800 p-3 rounded shadow-md max-w-2xl mx-auto">
<h2 class="text-xl text-lime-300 font-bold">
<%= link_to link.url, target: "_blank", class: 'hover:underline' do %>
<%= link_to track_click_link_path(link), target: "_blank", class: 'hover:underline' do %>
<i class="<%= link.icon %> text-lime-300"></i> <%= link.title %>
<% end %>
</h2>
Expand All @@ -65,7 +65,7 @@
<i class="<%= achievement.icon %> text-lime-300"></i>
<% end %>
<% if achievement.url.present? %>
<%= link_to achievement.title, achievement.url, class: 'text-lime-300 hover:underline', target: "_blank" %>
<%= link_to achievement.title, achievement_path(achievement), class: 'text-lime-300 hover:underline', target: "_blank" %>
<% else %>
<%= achievement.title %>
<% end %>
Expand Down
6 changes: 4 additions & 2 deletions config/application.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require_relative "boot"

require "rails/all"
require_relative "../app/middleware/page_view_tracker"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Expand All @@ -16,6 +16,8 @@ class Application < Rails::Application
# Common ones are `templates`, `generators`, or `middleware`, for example.
config.autoload_lib(ignore: %w(assets tasks))

config.middleware.use PageViewTracker

# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
Expand All @@ -24,4 +26,4 @@ class Application < Rails::Application
# config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")
end
end
end
6 changes: 6 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
}
end

resources :links do
member do
get :track_click
end
end

# Other routes
get "up" => "rails/health#show", as: :rails_health_check
root to: 'pages#home'
Expand Down
13 changes: 13 additions & 0 deletions db/migrate/20240818111049_create_page_views.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreatePageViews < ActiveRecord::Migration[7.1]
def change
create_table :page_views do |t|
t.references :user, null: false, foreign_key: true
t.string :path
t.string :referrer
t.string :browser
t.datetime :visited_at

t.timestamps
end
end
end
13 changes: 13 additions & 0 deletions db/migrate/20240818111055_create_link_clicks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreateLinkClicks < ActiveRecord::Migration[7.1]
def change
create_table :link_clicks do |t|
t.references :link, null: false, foreign_key: true
t.references :user, null: false, foreign_key: true
t.datetime :clicked_at
t.string :referrer
t.string :browser

t.timestamps
end
end
end
13 changes: 13 additions & 0 deletions db/migrate/20240818111101_create_achievement_views.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreateAchievementViews < ActiveRecord::Migration[7.1]
def change
create_table :achievement_views do |t|
t.references :achievement, null: false, foreign_key: true
t.references :user, null: false, foreign_key: true
t.datetime :viewed_at
t.string :referrer
t.string :browser

t.timestamps
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddIpAddressAndSessionIdToAchievementViews < ActiveRecord::Migration[7.1]
def change
add_column :achievement_views, :ip_address, :string
add_column :achievement_views, :session_id, :string
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddIpAddressAndSessionIdToLinkClicks < ActiveRecord::Migration[7.1]
def change
add_column :link_clicks, :ip_address, :string
add_column :link_clicks, :session_id, :string
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddIpAddressAndSessionIdToPageViews < ActiveRecord::Migration[7.1]
def change
add_column :page_views, :ip_address, :string
add_column :page_views, :session_id, :string
end
end
Loading

0 comments on commit a8ef003

Please sign in to comment.