mongodbmongoidruby-on-rails-3.2carrierwavegridfs

Config CarrierWave with Mongoid - GridFS


I am getting a trouble, trying to use CarrierWave for a file upload Rest API developed in Rails 3, with a MongoDB database.

What I would like to do is storing some files (not only images but every file format) with the MongoDB system GridFS. I read many documentations that recommend my to use the CarrierWave gem.

But I have an error when I try to configure it.

My development environment : The 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'

The application.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"

I define the database with a mongoid.yml (config/mongoid.yml) file :

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

And load it with an initializer (config/initializers/mongoid.rb) :

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

-- I can execute the "rails server" command without problems after the last file, config/initializers/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

And then get the following error when I run the "rails server" command :

=> 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)
[...]

My file model is defined as following :

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

The FileUploader is just an extension of CarrierWave uploader...

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

Solution

  • Sorry about the slow response. Firstly, the reason for your error is that Mongoid 3 no longer supports Mongoid.database. You can now find these configurations in the Mongoid::Config.sessions[:default] object.

    BUT THIS AIN'T GONNA FIX YOUR PROBLEM! Mongoid 3 has no GridFS support at all. From mongoid docs:

    No GridFS Support

    GridFS is marketed as a core database feature, when in fact it is not. It is simply a pattern for storing chunked file data as documents in a collection, just like any other document. The implementation of this behaviour is handled in the client drivers, not in the core database itself, which can lead to discrepencies in how this is handled across > platforms.

    Even if having this behaviour in the client is acceptable, the effects of this on application performance where you are not just storing file data is quite large. Since files are stored as documents, they consume RAM just as any other document in the database would, and can easily cause memory consumption on your server to max out. There are also limitations in chunking the data, such as you do not have the ability to update a file - you must delete the file and replace it with a new one.

    Given this, we did not prioritize any work with GridFS at the front, but there is a gem in the pipeline for those who can wait a bit to upgrade. In the meantime you have a few options...

    So rather than seek other ways to store uploads in the GridFS at the expense of performance, I would suggest just throwing them in a SQL database. If your using Mongo as your only database, don't be put off by this option. It's not very difficult to get ActiveRecord and Mongoid working together side-by-side. But from my experience, uploading binary objects to any database may not perform well. I would personally use a filesystem for storage, with carrierwave or paperclip taking care of the management. Alternatively, I would suggest checking out some cheap cloud storage options. You can use something like aws-s3, a great service. It also has very well documented compatibility with Carrierwave.

    If you are determined to use GridFS, I would check out the mongoid-grid_fs gem or check out some alternative ruby MongoDB drivers on the 10gen website.