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.
Written by Andrew Valish
Related protips
2 Responses
I am getting the following error undefined method `database' for Mongoid:Module
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 .