Search code examples
ruby-on-railsrails-activestorage

Implementing file request counter


I have a Rails API project.

I am trying to implement a counter on the number of times a file is requested, say, the number of times an audio file is played.

This is my model

class Post < ApplicationRecord
  has_one_attached :audio_file
end

The frontend gets the file URL and makes a GET request to play the file:

GET localhost:3001/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBDQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--75d7e21e4e3727c21cb0e26a86c7366dea1bc36a/test_audio.mp3

When the request is performed, rails logs this:

Started GET "/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBDQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--75d7e21e4e3727c21cb0e26a86c7366dea1bc36a/test_audio.mp3" for ::1 at 2020-05-13 20:29:15 -0400
   (28.4ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
  ↳ /home/david/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98

Processing by ActiveStorage::BlobsController#show as MP3
  Parameters: {"signed_id"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBDQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--75d7e21e4e3727c21cb0e26a86c7366dea1bc36a", "filename"=>"test_audio"}
  ActiveStorage::Blob Load (45.5ms)  SELECT  "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ /home/david/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
  Disk Storage (18882.5ms) Generated URL for file at key: XoA9L6bBFrEeBuGMRPzHx6Wn (http://localhost:3001/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9JYTJWNVNTSWRXRzlCT1V3MllrSkdja1ZsUW5WSFRWSlFla2g0TmxkdUJqb0dSVlE2RUdScGMzQnZjMmwwYVc5dVNTSkxZWFIwWVdOb2JXVnVkRHNnWm1sc1pXNWhiV1U5SW5SbGMzUmZZWFZrYVc4dWJYQXpJanNnWm1sc1pXNWhiV1VxUFZWVVJpMDRKeWQwWlhOMFgyRjFaR2x2TG0xd013WTdCa1k2RVdOdmJuUmxiblJmZEhsd1pVa2lEMkYxWkdsdkwyMXdaV2NHT3daVSIsImV4cCI6IjIwMjAtMDUtMTRUMDA6MzQ6NDUuMDMyWiIsInB1ciI6ImJsb2Jfa2V5In19--b7120a24370e1afd709601363c463950bbb6ad22/test_audio.mp3?content_type=audio%2Fmpeg&disposition=attachment%3B+filename%3D%22test_audio.mp3%22%3B+filename%2A%3DUTF-8%27%27test_audio.mp3)
Redirected to http://localhost:3001/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9JYTJWNVNTSWRXRzlCT1V3MllrSkdja1ZsUW5WSFRWSlFla2g0TmxkdUJqb0dSVlE2RUdScGMzQnZjMmwwYVc5dVNTSkxZWFIwWVdOb2JXVnVkRHNnWm1sc1pXNWhiV1U5SW5SbGMzUmZZWFZrYVc4dWJYQXpJanNnWm1sc1pXNWhiV1VxUFZWVVJpMDRKeWQwWlhOMFgyRjFaR2x2TG0xd013WTdCa1k2RVdOdmJuUmxiblJmZEhsd1pVa2lEMkYxWkdsdkwyMXdaV2NHT3daVSIsImV4cCI6IjIwMjAtMDUtMTRUMDA6MzQ6NDUuMDMyWiIsInB1ciI6ImJsb2Jfa2V5In19--b7120a24370e1afd709601363c463950bbb6ad22/test_audio.mp3?content_type=audio%2Fmpeg&disposition=attachment%3B+filename%3D%22test_audio.mp3%22%3B+filename%2A%3DUTF-8%27%27test_audio.mp3
Completed 302 Found in 21681ms (ActiveRecord: 54.2ms)

Started GET "/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9JYTJWNVNTSWRXRzlCT1V3MllrSkdja1ZsUW5WSFRWSlFla2g0TmxkdUJqb0dSVlE2RUdScGMzQnZjMmwwYVc5dVNTSkxZWFIwWVdOb2JXVnVkRHNnWm1sc1pXNWhiV1U5SW5SbGMzUmZZWFZrYVc4dWJYQXpJanNnWm1sc1pXNWhiV1VxUFZWVVJpMDRKeWQwWlhOMFgyRjFaR2x2TG0xd013WTdCa1k2RVdOdmJuUmxiblJmZEhsd1pVa2lEMkYxWkdsdkwyMXdaV2NHT3daVSIsImV4cCI6IjIwMjAtMDUtMTRUMDA6MzQ6NDUuMDMyWiIsInB1ciI6ImJsb2Jfa2V5In19--b7120a24370e1afd709601363c463950bbb6ad22/test_audio.mp3?content_type=audio%2Fmpeg&disposition=attachment%3B+filename%3D%22test_audio.mp3%22%3B+filename%2A%3DUTF-8%27%27test_audio.mp3" for ::1 at 2020-05-13 20:29:46 -0400
Processing by ActiveStorage::DiskController#show as MP3
  Parameters: {"content_type"=>"audio/mpeg", "disposition"=>"attachment; filename=\"test_audio.mp3\"; filename*=UTF-8''test_audio.mp3", "encoded_key"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9JYTJWNVNTSWRXRzlCT1V3MllrSkdja1ZsUW5WSFRWSlFla2g0TmxkdUJqb0dSVlE2RUdScGMzQnZjMmwwYVc5dVNTSkxZWFIwWVdOb2JXVnVkRHNnWm1sc1pXNWhiV1U5SW5SbGMzUmZZWFZrYVc4dWJYQXpJanNnWm1sc1pXNWhiV1VxUFZWVVJpMDRKeWQwWlhOMFgyRjFaR2x2TG0xd013WTdCa1k2RVdOdmJuUmxiblJmZEhsd1pVa2lEMkYxWkdsdkwyMXdaV2NHT3daVSIsImV4cCI6IjIwMjAtMDUtMTRUMDA6MzQ6NDUuMDMyWiIsInB1ciI6ImJsb2Jfa2V5In19--b7120a24370e1afd709601363c463950bbb6ad22", "filename"=>"test_audio"}
Completed 200 OK in 1ms (ActiveRecord: 0.0ms)

I was thinking of adding a callback to ActiveStorage::Blob Load, that +1 a counter attribute in the Post model. My idea was to use after_find but I am not sure where I should add it.

Any other suggestions are very much appreciated.


Solution

  • How about providing new member action for posts_controller and use rails_blob_path helper?

    in routes.rb definition

    resources :posts do
      member do
        get :download
      end
    end
    

    in controller

    class PostsController::ApplicationController
      def download
        post = Post.find params[:id]
    
        # counter business logic here
        post.increment(:download_counter)
    
        rails_blob_path(post.audio_file, disposition: "attachment")
      end
    end