8

我知道 ActiveStorageurl_for(user.avatar)方法。例子:

<%= link_to "Download this file", url_for(@user.avatar) %>

这很棒,但似乎没有围绕它建立的授权。知道此链接的任何人都可以下载此文档。

过去当我使用回形针时,我有一个指向自定义控制器操作的链接。该自定义控制器操作进行了授权,如果一切正常,那么我曾经send_file将文件发送给用户。是这样的:

def deliver_the_file
  authorize :my_authorization
  send_file @user.avatar.path
end

如何使用 active_storage 做到这一点?我所做的只是url_for完全不授权用户的实现。

我正在专门查看有关 ActiveStorage 的 Rails 指南的下载文件部分。

相关示例代码:

# model 
class Book < ApplicationRecord
  has_one_attached :book_cover
end


class BooksController < ApplicationController
 ... 

  # custom action to authorize and then deliver the active_storage file
  def deliver_it
    # ... assume authorization already happened
    send_file rails_blob_path(@book.book_cover, disposition: "attachment")
  end
end

这错误并说:

无法读取文件

我也尝试过这个:

def deliver_it
  # ... assume authorization already happened
  send_file @book.book_cover.download
end

这返回了错误:

字符串包含空字节

我也尝试过这个:

def deliver_it
  @book.book_cover.download
end

这返回了错误:

BooksController#deliver_it 缺少此请求的模板

我也试过这个:

def deliver_it
  send_file @book.book_cover.blob
end

这错误并说:

没有将 ActiveStorage::Blob 隐式转换为 String

4

3 回答 3

10

最好的办法是使用ActiveStorage::Blob#service_url重定向到 blob 的已签名的、短暂的 URL:

class Books::CoversController < ApplicationController
  before_action :set_active_storage_host, :set_book

  def show
    redirect_to @book.cover.service_url
  end

  private
    def set_active_storage_host
      ActiveStorage::Current.host = request.base_url
    end

    def set_book
      @book = Current.person.books.find(params[:book_id])
    end
end

或者,您自己提供文件。您可以使用ActionController::Live将文件流式传输到客户端,而不是一次将整个文件读入内存。

class Books::CoversController < ApplicationController
  include ActionController::Live

  before_action :set_book

  def show
    response.headers["Content-Type"] = @book.cover.content_type
    response.headers["Content-Disposition"] = "attachment; #{@book.cover.filename.parameters}"

    @book.cover.download do |chunk|
      response.stream.write(chunk)
    end
  ensure
    response.stream.close
  end

  # ...
end
于 2018-05-11T00:01:02.227 回答
9

我从对此ActiveStorage 问题的评论中得出此解决方案

def deliver_it
  send_data @book.book_cover.download, filename: @book.book_cover.filename.to_s, content_type: @book.book_cover.content_type
end
于 2018-05-10T23:54:45.877 回答
3

redirect_to在这里使用过并且有效:

redirect_to rails_blob_path(@book.book_cover, disposition: "attachment")
于 2018-09-17T21:47:01.670 回答