0

我遇到了麻烦,试图将 CarrierWave 用于在 Rails 3 中开发的文件上传 Rest API 和 MongoDB 数据库。

我想做的是使用 MongoDB 系统 GridFS 存储一些文件(不仅是图像,而且是每种文件格式)。我阅读了许多建议我使用 CarrierWave gem 的文档。

但是当我尝试配置它时出现错误。

我的开发环境:Gemfile:

source 'https://rubygems.org'

gem 'rails', '3.2.8'

# MongoDB
gem 'mongoid', :git => 'git://github.com/mongoid/mongoid.git'
gem 'carrierwave', :git => "git://github.com/jnicklas/carrierwave.git"
# gem 'carrierwave-mongoid', :require => 'carrierwave/mongoid'
gem 'mini_magick', :git => 'git://github.com/probablycorey/mini_magick.git'

gem 'bson_ext'
gem 'json'

应用程序.rb :

require File.expand_path('../boot', __FILE__)

# ActiveRecord will not be use with MongoDB
# require 'rails/all'
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "rails/test_unit/railtie"
require "sprockets/railtie"
require "mongoid/railtie"
require "carrierwave"
# require "carrierwave/mongoid"

我使用 mongoid.yml (config/mongoid.yml) 文件定义数据库:

development:
  sessions:
    default:
      database: lf_rest_api_development
      hosts:
        - localhost:27017
      options:
        consistency: :strong
  options:

test:
  sessions:
    default:
      database: lf_rest_api_test
      hosts:
        - localhost:27017
      options:
        consistency: :strong

并使用初始化程序 (config/initializers/mongoid.rb) 加载它:

Mongoid.load!("config/mongoid.yml")

-- 在最后一个文件 config/initializers/carrierwave.rb 之后,我可以毫无问题地执行“rails server”命令:

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

然后当我运行“rails server”命令时出现以下错误:

=> Booting WEBrick
=> Rails 3.2.8 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
Exiting
/{API_path}/config/initializers/zcarrierwave.rb:4:in `block in <top (required)>': undefined method `database' for Mongoid:Module (NoMethodError)
[...]

我的文件模型定义如下:

require 'carrierwave/orm/mongoid'

class File
    include Mongoid::Document
    store_in_collection: "files", database: "lf_rest_api_developement", session: "default"

    key :filename, type: String
    key :content_type, type: String
    key :length, type: BigDecimal
    key :chunk_size, type: Integer, :default => 256
    key :upload_date, type: DateTime
    key :md5, type: String
    key :metadata, type: Array, :default => []

    mount_uploader :file, FileUploader

    index({ location: "2d" }, { min: -200, max: 200 })
end

FileUploader 只是 CarrierWave 上传器的扩展......

class FileUploader < CarrierWave::Uploader::Base
    storage :grid_fs
end
4

2 回答 2

7

抱歉回复慢。首先,您的错误原因是 Mongoid 3 不再支持Mongoid.database. 您现在可以在Mongoid::Config.sessions[:default]对象中找到这些配置。

但这不会解决您的问题!Mongoid 3 根本不支持 GridFS。来自mongoid 文档

不支持 GridFS

GridFS 被作为核心数据库功能推向市场,但实际上并非如此。它只是一种将分块文件数据存储为集合中的文档的模式,就像任何其他文档一样。此行为的实现在客户端驱动程序中处理,而不是在核心数据库本身中处理,这可能导致跨平台处理方式的差异。

即使在客户端中具有这种行为是可以接受的,但在您不只是存储文件数据的情况下,这对应用程序性能的影响是相当大的。由于文件存储为文档,因此它们会像数据库中的任何其他文档一样消耗 RAM,并且很容易导致服务器上的内存消耗达到最大值。分块数据也有限制,例如您无法更新文件 - 您必须删除文件并用新文件替换它。

鉴于此,我们没有优先考虑在前面使用 GridFS 的任何工作,但对于那些可以等待升级的人来说,有一个宝石正在筹备中。与此同时,你有几个选择......

因此,与其以牺牲性能为代价寻求其他方式将上传存储在 GridFS 中,我建议将它们放入 SQL 数据库中。如果你使用 Mongo 作为你唯一的数据库,不要被这个选项推迟。让 ActiveRecord 和 Mongoid 并肩工作并不难。但根据我的经验,将二进制对象上传到任何数据库都可能效果不佳。我个人会使用文件系统进行存储,使用carrierwave或回形针负责管理。或者,我建议查看一些便宜的云存储选项。您可以使用 aws-s3 之类的东西,这是一项很棒的服务。它还与 Carrierwave 有很好的兼容性。

如果您决定使用 GridFS,我会查看mongoid-grid_fs gem 或查看 10gen 网站上的一些替代 ruby​​ MongoDB 驱动程序。

于 2012-10-25T19:30:34.563 回答
6

这是我第一次回答问题,所以我希望我做对了。

我在使用 Mongoid 3 的 rails 应用程序中使用载波上传图像时遇到了同样的问题。我相信我有一个解决方案(至少让它在我的笔记本电脑上本地工作。)这是我想出的:

使用 branch 将carrierwave-mongoid gem添加到您的gemfile 中mongoid-3.0。这个 gem 使用mongoid-grid_fs

# Image Uploading
gem "carrierwave-mongoid", :git => "git://github.com/jnicklas/carrierwave-mongoid.git", :branch => "mongoid-3.0"

为载波做一个初始化器:

#config/initializers/carrierwave.rb
CarrierWave.configure do |config|

  config.storage = :grid_fs

  # Storage access url
  config.grid_fs_access_url = "/upload/grid"
end

我知道我没有设置config.grid_fs_databaseconfig.grid_fs_host。这似乎在本地工作(在我的笔记本电脑上)我没有尝试使用远程 gridfs 数据库。

安装看起来很正常:

#app/models/user.rb
class User
  include Mongoid::Document
  mount_uploader :avatar, AvatarUploader
end

上传器也是标准的:

#app/uploaders/avatar_uploader
class AvatarUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  def store_dir
    "#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  version :thumb do
    process :resize_to_limit => [200, 200]
  end
end

为 GridFS 创建一个控制器:

#app/controllers/gridfs_controller.rb
class GridfsController < ApplicationController

  def serve
    gridfs_path = env["PATH_INFO"].gsub("/upload/grid/", "")
    begin
      gridfs_file = Mongoid::GridFS[gridfs_path]
      self.response_body = gridfs_file.data
      self.content_type = gridfs_file.content_type
    rescue
      self.status = :file_not_found
      self.content_type = 'text/plain'
      self.response_body = ''
    end
  end
end

并将路由添加到路由文件:

#config/routes.rb
match "/upload/grid/*path" => "gridfs#serve"

希望这可以帮助。

于 2012-12-01T23:13:17.617 回答