Search code examples
ruby-on-rails-5rails-activestorage

How to update the database when users download an ActiveStorage blob attachment?


Currently users can download an ActiveStorage blob in my app using the following link:

link_to 'download', rails_blob_path(pj.document.file, disposition: 'attachment')

However, I would like to update an attribute in the database for the associated model to register when the file was first downloaded. This field is called the downloaded_at field.

I have made the following attempt:

  1. Changed the link_to > button_to as I'm updating the model.
  2. Added the appropriate route
  3. Added the following code in the database:

    def download
        @proofreading_job = ProofreadingJob.find(params[:id])
        @proofreading_job.update(downloaded_at: Time.current) if current_user == @proofreading_job.proofreader.user
        response.headers["Content-Type"] = @proofreading_job.document.file.content_type
        response.headers["Content-Disposition"] = "attachment; #{@proofreading_job.document.file.filename.parameters}"
    
        @proofreading_job.document.file.download do |chunk|
          response.stream.write(chunk)
        end
        ensure
        response.stream.close
    end
    

However, this does not do anything except redirect to the @proofreading_job page which is not what I want.

Has anyone done this before and if so how can I accomplish this task.


Solution

  • In the end I just used some javascript to capture the click of the button as follows:

        td = link_to rails_blob_path(pj.document.file, disposition: 'attachment'), 
             id: pj.document.id, 
       download: pj.document.file_name, 
          class: "btn btn-outline-secondary btn-sm btn-download" do
            =pj.document.file_name 
            i.fa.fa-download.ml-3 aria-hidden="true"
    

    coffee script:

      $('.btn-download').on 'click', (e) ->
        id = $(this).attr('id')
        $.ajax {url: Routes.document_path(id), type: 'PUT'}
    

    routes.rb

    resources :documents, only: [:show, :update]
    

    documents_controller.rb:

      def update
        document = Document.find(params[:id])
        authorize([:proofreaders, document]) 
        document.update(downloaded_at: Time.current) if document.downloaded_at.nil?
        head :ok
      end
    

    This seems to work very well. It updates the database and the user gets the file downloaded to their computer.