Last Updated: February 25, 2016
·
8.972K
· valish

Rails 3; Mongoid; GridFS; Carrierwave Image Upload

I've been having difficulty getting file uploading to work on Rails 3 with Mongoid using Carrierwave & MongoDB's GridFS, so I decided to share a working solution after piecing it together.

In this tutorial we're using Devise for authentication and adding profile photos to user accounts.

1) Add to Gemfile:

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'

2) Run bundle install command

3) Add to config/application.rb:

require "mongoid/railtie"

4) Run rails g uploader profile_photo to generate the uploader file

5) Edit uploaders/profilephotouploader.rb file:

require 'carrierwave/processing/mini_magick'

class ProfilePhotoUploader < CarrierWave::Uploader::Base

  include CarrierWave::MiniMagick
  include Sprockets::Helpers::RailsHelper
  include Sprockets::Helpers::IsolatedHelper

  storage :grid_fs

   # Override the directory where uploaded files will be stored.
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

   # Create different versions of your uploaded files:
   version :thumb do
     process :scale => [55, 55]
   end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  def default_url
    asset_path("fallback/" + [version_name, "default-photo.png"].compact.join('_'))
  end

end

6) Mount the uploader to your model user.rb:

mount_uploader :profile_photo, ProfilePhotoUploader

7) Create config/initializers/carrierwave.rb file:

CarrierWave.configure do |config|

  config.storage              = :grid_fs
  config.grid_fs_access_url   = "/images"
  config.grid_fs_database     = Mongoid.database.name

  if Rails.env.production?
    config.grid_fs_database   = ENV['MONGOID_DATABASE'] || Mongoid.database.name
    config.grid_fs_host       = ENV['MONGOID_HOST']
    config.grid_fs_port       = ENV['MONGOID_PORT']
    config.grid_fs_username   = ENV['MONGOID_USERNAME']
    config.grid_fs_password   = ENV['MONGOID_PASSWORD']
  end

end

8) Create controllers/gridfs_controller.rb file:

require 'mongo'

class GridfsController < ActionController::Metal

    def serve
    gridfs_path = env["PATH_INFO"].gsub("/images/", "")
    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

8) Add to routes.rb file:

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

9) Add to form view file - views/devise/registrations/new.html.erb

<%= f.file_field :profile_photo %>

10) Add to view file to display photo - views/users/show.html.erb:

<!-- full size image -->
<%= image_tag @user.profile_photo_url %>

<!-- thumbnail image -->
<%= image_tag @user.profile_photo_url(:thumb) %> 

Enjoy! Feedback appreciated.

2 Responses
Add your response

I am getting the following error undefined method `database' for Mongoid:Module

over 1 year ago ·

I am getting issues with gridfs file system when try to retrieve files from gridfs, I could able to store files(text,pdf) using carrierwave mongoid gridfs and unable to get the data from the mongodb , Can anyone please help me

I uploaded sample text file into gridfs , it stored the file content in database please look at the following record where you can see the actual record from database

email id:="" 547f17f37261740ea9000000,="" from:="" "mail@gmail.com",="" to:="" "mail@gmail.com",="" cc:="" nil,="" bcc:="" nil,="" subject:="" "testmail",="" body:="" "h1.="" give="" redcloth="" a="" try!="" a="" simple="" paragraph="" with="" a="" line="" break="" ,="" someemphasis_and="" a="" \"link\":http:="" redcloth.org",="" attachment1:="" bson::binary:0xe129374="" @data="this is a simple file a couple of lines long\nsecond line\nthird line" ,="" @type=":generic", attachment2: nil, attachment3: nil>

see the field attachment1 it show you the gridfs content and @data stores my actual file content , upto this all is fine , but when I try to get the data from this record I am unable to get it , I tried like the following

@email.attachment1.read ==> shows me nil value

@email.attachment1.file.read => also shows me nil value

also tried @email.instancevariableget(:@data) ==> not worked

How to fix this , please help me .

over 1 year ago ·