8

私は ActiveStorageurl_for(user.avatar)メソッドを認識しています。例:

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

これは素晴らしいことですが、その周りに承認が組み込まれていないようです。このリンクを知っている人は誰でもこのドキュメントをダウンロードできます。

過去にpaperclipを使用したとき、カスタム コントローラー アクションへのリンクがありました。そのカスタム コントローラー アクションは認証を行い、すべてが良好であればsend_file、ファイルをユーザーに送信していました。それは次のようなものでした:

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

active_storage でこれを行うにはどうすればよいですか? 私が仕事をしたのurl_forは、ユーザーをまったく承認しない実装だけです。

具体的には、Rails Guides on ActiveStorage のDownload Files部分を調べています。

関連するコード例:

# 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

これはエラーを返しました:

文字列に null バイトが含まれています

そして、私もこれを試みました:

def deliver_it
  @book.book_cover.download
end

これはエラーを返しました:

BooksController#deliver_it には、このリクエストのテンプレートがありません

私もこれを試しました:

def deliver_it
  send_file @book.book_cover.blob
end

これはエラーになり、次のように表示されます。

ActiveStorage::Blob から文字列への暗黙的な変換はありません

4

3 に答える 3

10

Your best bet is to use ActiveStorage::Blob#service_url to redirect to a signed, short-lived URL for the blob:

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

Alternatively, serve the file yourself. You can use ActionController::Live to stream the file to the client instead of reading the entire file into memory at once.

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 に答える