如何从rails模型中打开CarrierWave在GridFs中存储的文件? (File.open问题)

时间:2011-11-01 17:15:31

标签: ruby-on-rails ruby mongodb carrierwave

我正在使用CarrierWave将文件存储在gridfs中,但是从我的模型中打开它们时遇到了问题。 这是我的配置:

/config/initialize/carrierwave.rb

 CarrierWave.configure do |config|
  config.grid_fs_database = Mongoid.database.name
  config.grid_fs_host = Mongoid.config.master.connection.host
  config.storage = :grid_fs
  config.grid_fs_access_url = "/files"
end

/app/controllers/gridfs_controller.rb

 /require 'mongo' 
        class GridfsController < ActionController::Metal
          def serve
            gridfs_path = env["PATH_INFO"].gsub("/files/", "")
            begin
              gridfs_file = Mongo::GridFileSystem.new(Mongoid.database).open(gridfs_path, 'r')
              self.response_body = gridfs_file.read
              self.content_type = gridfs_file.content_type
            rescue
              self.status = :file_not_found
              self.content_type = 'text/plain'
              self.response_body = ''
            end
          end
        end

/app/uploaders/list_uploader.rb

class ListUploader < CarrierWave::Uploader::Base
  storage :grid_fs
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

和路线

match "/files/uploads/*path" => "gridfs#serve"

所以,我有一个模型,它有一个文本文件

class Campaign
  include Mongoid::Document
  mount_uploader :list, ListUploader

当我从我的视图中调用类似<%=link_to "List", @campaign.list.url %>的内容时,它打开正常。但是,当我从广告系列模型尝试类似File.open("#{campaign.list.url}", "r")的内容时,它会失败。即使我正在调用false,它也会给我File.exists?("/files/uploads/campaign/list/4eb02c4d6b1c0f02b200000b/list.txt"),这是该文件的正确网址。那么,问题是如何调用它,从模型中打开文件?由于某些原因,从模型中打开它很重要。任何建议都会有所帮助,谢谢。

1 个答案:

答案 0 :(得分:2)

带有mongodb gridfs的Carrierwave网址不是物理路径。它只是从gridfs下载文件的逻辑路径。这就是为什么你不能从ruby File.open访问它。从rails console尝试从gridfs

打开文件,查看下面的代码片段
File.open(User.first.image.pic.url,'r')
Errno::ENOENT: No such file or directory - /images/uploads/e5a1007d34.jpg

看到它抛出没有这样的文件或目录。所以你必须下载文件而不是打开

>> require 'open-uri'
>> open('image.jpg', 'wb') do |file|
?> file << open('http://0.0.0.0:3000' + (User.first.image.pic.url)).read
>> p file
>> end
#<File:image.jpg>
=> #<File:image.png (closed)>