Config CarrierWave с Mongoid - GridFS

Я получаю проблемы, пытаясь использовать CarrierWave для загрузки API Rest API, разработанного в Rails 3, с базой данных MongoDB.

Я хотел бы сохранить некоторые файлы (не только изображения, но и файлы любого формата) с помощью системы MongoDB GridFS. Я прочитал много документов, которые рекомендуют мне использовать драгоценный камень CarrierWave.

Но у меня возникает ошибка при попытке настроить его.

Моя среда разработки: 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'

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"

Я определяю базу данных с помощью файла 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/ initializer / mongoid.rb):

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

- я могу без проблем выполнить команду "rails server" после последнего файла, 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

И тогда я получаю следующую ошибку при запуске команды "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

2 ответа

Решение

Извините за медленный ответ. Во-первых, причина вашей ошибки в том, что Mongoid 3 больше не поддерживает Mongoid.database, Теперь вы можете найти эти конфигурации в Mongoid::Config.sessions[:default] объект.

НО ЭТО НЕ ЧТОБЫ ИСПРАВИТЬ ВАШУ ПРОБЛЕМУ! Mongoid 3 вообще не поддерживает GridFS. Из документов mongoid:

Нет поддержки GridFS

GridFS продается как основная функция базы данных, хотя на самом деле это не так. Это просто шаблон для хранения данных фрагментированного файла в виде документов в коллекции, как и любой другой документ. Реализация этого поведения осуществляется в драйверах клиента, а не в самой базовой базе данных, что может привести к несоответствиям в том, как это обрабатывается на> платформах.

Даже если такое поведение на клиенте приемлемо, его влияние на производительность приложения, когда вы не просто храните данные файла, довольно велико. Поскольку файлы хранятся в виде документов, они потребляют оперативную память точно так же, как любой другой документ в базе данных, и могут легко привести к максимальному потреблению памяти на вашем сервере. Существуют также ограничения по фрагментации данных, например, у вас нет возможности обновить файл - вы должны удалить файл и заменить его новым.

Учитывая это, мы не расставили приоритеты для какой-либо работы с GridFS на фронте, но есть жемчужина в конвейере для тех, кто может немного подождать, чтобы обновить. А пока у вас есть несколько вариантов...

Поэтому вместо того, чтобы искать другие способы хранения загрузок в GridFS за счет производительности, я бы предложил просто выбросить их в базу данных SQL. Если вы используете Mongo в качестве единственной базы данных, не откладывайте эту опцию. Не так сложно заставить ActiveRecord и Mongoid работать вместе. Но по моему опыту, загрузка бинарных объектов в любую базу данных может не работать хорошо. Я лично использовал бы файловую систему для хранения, с несущей волной или скрепкой, заботящейся об управлении. В качестве альтернативы, я бы предложил проверить несколько дешевых вариантов облачного хранения. Вы можете использовать что-то вроде aws-s3, отличный сервис. Он также имеет очень хорошо задокументированную совместимость с Carrierwave.

Если вы решили использовать GridFS, я бы посмотрел гем mongoid-grid_fs или некоторые альтернативные драйверы ruby ​​MongoDB на веб-сайте 10gen.

Я впервые отвечаю на вопрос, поэтому надеюсь, что все делаю правильно.

Я боролся с той же проблемой при загрузке изображения с использованием несущей волны в моем приложении rails с Mongoid 3. Я считаю, что у меня есть решение (по крайней мере, оно работает локально на моем ноутбуке). Вот что я придумал:

Добавьте в свой gemfile кавалер-несущую- монгоид с веткой mongoid-3.0, Этот драгоценный камень использует 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_database или же config.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"

Надеюсь это поможет.

Другие вопросы по тегам