From b3a76289cc88b9f5426a6453751076eb8c9d4823 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 29 May 2025 17:01:38 +0530 Subject: [PATCH] feat: use tracking pixel for article view count (#11559) --- .../api/v1/portals/articles_controller.rb | 18 +++++++- app/views/layouts/portal.html.erb | 24 +++++++++++ config/routes.rb | 1 + public/assets/images/tracking-pixel.png | Bin 0 -> 123 bytes .../v1/portals/articles_controller_spec.rb | 40 +++++++++++++++++- 5 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 public/assets/images/tracking-pixel.png diff --git a/app/controllers/public/api/v1/portals/articles_controller.rb b/app/controllers/public/api/v1/portals/articles_controller.rb index d07dbcb9d..32a147d34 100644 --- a/app/controllers/public/api/v1/portals/articles_controller.rb +++ b/app/controllers/public/api/v1/portals/articles_controller.rb @@ -1,7 +1,7 @@ class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::BaseController before_action :ensure_custom_domain_request, only: [:show, :index] before_action :portal - before_action :set_category, except: [:index, :show] + before_action :set_category, except: [:index, :show, :tracking_pixel] before_action :set_article, only: [:show] layout 'portal' @@ -15,6 +15,21 @@ class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::B def show; end + def tracking_pixel + @article = @portal.articles.find_by(slug: permitted_params[:article_slug]) + return head :not_found unless @article + + @article.increment_view_count if @article.published? + + # Serve the 1x1 tracking pixel with 24-hour private cache + # Private cache bypasses CDN but allows browser caching to prevent duplicate views from same user + expires_in 24.hours, public: false + response.headers['Content-Type'] = 'image/png' + + pixel_path = Rails.public_path.join('assets/images/tracking-pixel.png') + send_file pixel_path, type: 'image/png', disposition: 'inline' + end + private def limit_results @@ -39,7 +54,6 @@ class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::B def set_article @article = @portal.articles.find_by(slug: permitted_params[:article_slug]) - @article.increment_view_count if @article.published? @parsed_content = render_article_content(@article.content) end diff --git a/app/views/layouts/portal.html.erb b/app/views/layouts/portal.html.erb index c4135fd37..6ed0c8201 100644 --- a/app/views/layouts/portal.html.erb +++ b/app/views/layouts/portal.html.erb @@ -73,6 +73,30 @@ By default, it renders: <% end %> + <% if @article.present? %> + + <% end %>