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

时间:2016-12-26 23:56:21

标签: ruby-on-rails ruby carrierwave

我正在制作带付费下载的网络应用程序,并且我遵循了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},所以该文件将保存在名为downloads的公用文件夹外部的文件夹中。然而,这会产生意想不到的副作用。当我从模型中检索URL时,我得到了整个绝对路径,而不是相对于Rails Root的路径。

例如,ProductFile.first.file.url会返回"/home/doomy/Documents/resamplr/downloads/3/1/aaaa.zip",而应返回/downloads/3/1/aaa.zip

此行为似乎附加在ProductFileUploader

中指定的内容

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

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

编辑:

我发现将Carrierwave配置文件中的config.root设置为Rails.root可以解决此问题。如果我执行此操作,请在我的ProductFileUploader中将store_dir指定为"downloads/#{model.product_id}/#{model.id}

但是,这意味着使用“/ public / ...”链接保存公共文件。 Rails会自动丢弃公共foldername并在URL中使用子目录名称。

1 个答案:

答案 0 :(得分:1)

了解如何解决这个问题!

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

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/..."。这意味着我可以使用控制器来限制访问。

然而,在我的公共上传者中,我只是......

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

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

/public/downloads/myfile.jpg

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

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

它会正确上传和显示图像!希望这可以帮助别人。