统计特定用户通过 Active Storage 下载文件的次数

Count the number of times a specific user downloaded files through Active Storage

我的 Post评论 模型都有 has_one_attached :file。我想做的是计算特定用户下载 post 文件或评论文件的次数。在 User 模型上创建一种 download_counter_cache,每当该用户下载文件时该模型就会递增。我怎样才能做到这一点?

根据 Max 的回答更新

这就是我目前所做的:

# Migration file
class CreateDownloads < ActiveRecord::Migration[6.0]
  def change
    create_table :downloads do |t|
      t.references :user, null: false, foreign_key: true
      t.references :resource, polymorphic: true

      t.timestamps
    end
  end
end
# Routes.rb
 concern :downloadable do
   resources :downloads, only: :create
 end

 resources :posts, concerns: :downloadable do
   [...] # Routes such as like/dislike
   resources :comments, concerns: :downloadable do
     [...] # Routes such as like/dislike
   end
 end
# In posts/_post.html.erb
<%= link_to([@post, :downloads], html_options = {class: 'file w-100'}, method: :post) do %>
  [...]
<% end %>

我的 downloads_controller 与 Max 的回答中建议的完全相同,我的 Post、评论、用户和下载模型也是如此。

问题是,每当我尝试下载时,它都会将我重定向到显然不存在的 downloads#index。我不确定我应该如何创建 resource class.

您必须首先在用户和 comments/posts table 之间添加连接 table 或直接添加到 activesupport 附件 table.

class Download
  belongs_to :user
  belongs_to :resource, polymorphic: true
end

class Post
  has_many :downloads, as: :resource
end

class Comment
  has_many :downloads, as: :resource
end

class User
  has_many :downloads
end

然后您必须创建一个 rails 控制器来代理下载,因为下载 ActiveSupport 附件通常会完全绕过您的 Rails 应用程序并直接从存储附件的服务(例如 S3)下载.

class DownloadsController < ApplicationController
  before_action :authenticate_user! # I'm assuming you're using Devise
  before_action :set_resource

  def create
    @download = @resource.downloads.create!(user: current_user)
    redirect_to @resource.file.service_url
  end

  def set_resource
    if params[:post_id]
      @resource = Post.find(params[:post_id])
    elsif params[:comment_id]
      @resource = Comment.find(params[:comment_id])
    end
  end
end
# routes.rb
concern :downloadable do
  resources :downloads, only: :create
end
resources :posts, concerns: :downloadable
resources :comments, concerns: :downloadable
<%= button_to "Download", [@post, :downloads], method: :post %>

然后您可以通过计算下载中的行数来计算下载量 table。

max 有一个很好的答案,但如果您只想在用户模型上只有一列来计算所有下载,则可以在没有多态连接的情况下完成 table。

让我们向用户模块添加一个属性来存储计数:

  add_column :users, :download_count, :integer

然后添加一个控制器来处理计数并重定向到下载的文件:

class DownloadsController < ApplicationController
  def create
    # using find_by so it doesn't throw any errors
    resource = Post.find_by_id(params[:post_id]) || Comment.find_by_id(params[:comment_id])

    if resource
      current_user.increment!(:download_count)
      redirect_to rails_blob_path(resource.file, disposition: "attachment")
    else
      render nothing: true
    end
  end
end

路线如下:

  resources :downloads, only: :create

下载 link 在视图中看起来像:

# for post file
<%= link_to 'download file', downloads_path(post_id: @post.id), method: :post %>

# for comment file
<%= link_to 'download file', downloads_path(comment_id: comment.id), method: :post %>

就这么简单。


更新:将方法从新方法更改为 post 以防止双重渲染。