显示 Rails 载波 URL 而不暴露整个路径

Show Rails Carrierwave URL without exposing entire path

我正在制作一个付费下载的网络应用程序,我遵循了 Carrierwave 的 protecting uploads 指南。除一件事外,一切都按预期进行。这是我当前的设置:


产品文件上传器

...
def store_dir
    "#{Rails.root}/downloads/#{model.product_id}/#{model.id}"
end
...

路线

  get "/downloads/:product_id/:product_file_id/:filename", :controller => "products", action: "download", conditions: {method: :get}

ProductsController

def download
  product_file = ProductFile.find(params[:product_file_id])
  name = File.basename(product_file.file.file.file)
  send_file "#{Rails.root}/downloads/#{product_file.product.id}/#{product_file.id}/#{name}", :x_sendfile => true
end

下载路径有问题。因为我在文件上传器中指定了 #{Rails.root},所以文件保存在 public 文件夹外部的一个名为 downloads 的文件夹中。然而,这有一个意想不到的副作用。当我从我的模型中检索 URL 时,我得到了整个绝对路径,而不是相对于 Rails 根目录的路径。

例如,ProductFile.first.file.url returns "/home/doomy/Documents/resamplr/downloads/3/1/aaaa.zip",当它应该只是 return /downloads/3/1/aaa.zip.

此行为似乎与 ProductFileUploader 中指定的内容有关。

例如,如果我将 store_dir 更改为 "/downloads/#{model.product_id}/#{model.id}",我会收到一个访问错误,因为它正在尝试上传到我的 PC 的根目录。 "downloads/#{model.product_id}/#{model.id}" 只是上传到 public 目录中名为 downloads 的新文件夹,这不是我想要做的。

关于如何进行的任何建议?谢谢。


编辑:

我发现将 Carrierwave 配置文件中的 config.root 设置为 Rails.root 可以实现此行为。如果我这样做,在我的 ProductFileUploader 中我可以将 store_dir 指定为 "downloads/#{model.product_id}/#{model.id}.

但是,这意味着 public 文件保存为“/public/...”link。 Rails 自动丢弃 public 文件夹名称并使用 URL.

中的子目录名称

找到解决方法了!

在每个上传器中,都有一个名为root的特殊方法,我们可以使用它来设置看不见的文件路径。首先,我制作了一个名为 PublicUploader 的特殊上传器库 class。

class PublicUploader < CarrierWave::Uploader::Base
  def root
    "${Rails.root}/public"
  end
end

然后,我将全局 CarrierWave 根设置为 Rails.root。

CarrierWave.configure do |config|
  # These permissions will make dir and files available only to the user running
  # the servers
  config.permissions = 0600
  config.directory_permissions = 0700
  config.storage = :file

  # This avoids uploaded files from saving to public/ and so
  # they will not be available for public (non-authenticated) downloading
  config.root = Rails.root
end

这意味着在我的私人文件上传器中我可以简单地写

def store_dir
  "downloads/#{model.product_id}/#{model.id}"
end

它将保存在 "#{Rails.root}/downloads/..." 而不是 "#{Rails.root}/public/downloads/..."。这意味着我可以使用控制器来限制访问。

然而,在我的 public 上传器中,我只是......

def store_dir
  "public/downloads/#{model.product_id}/#{model.id}"
end

...因为我想保存在我的 "#{Rails.root}/public" 文件夹中。但是,这意味着 rails 会显示如下 url

/public/downloads/myfile.jpg

这带来了一个问题,因为 Rails 从路径中省略了 public。所以上面会是 404。然而,当上传者从我定义 root 的特殊 class 继承时,我可以简单地说

def store_dir
  "downloads/#{model.product_id}/#{model.id}"
end

它将正确上传并显示图像!希望这可以帮助某人。