Save a pdf in mongodb with mongoid without GridFS

1.1k views Asked by At

I want to save a small pdf file in a mongodb database. I use Ruby (2.0.0), Padrino (0.12.5) and MongoId (3.0.0), MongoDB(2.6). Since my filesize is around 1MB, I will not need the complexity of GridFS.

I am new to MongoDB and expected that small files can be easily saved without worrying about paths and the filesystem.

class Client
  include Mongoid::Document
  include Mongoid::Timestamps # adds created_at and updated_at fields

  field :last_name, :type => String
  field :cv_pdf, :type => Moped::BSON::Binary
 end

If I use a test file in the console I get an error when I want to save the pdf file to the DB:

2.0.0-p353 :015 >   c = Client.first
    => #<Client _id: 55883b5168874459df000001, _type: nil, created_at: 2015-06-22 16:44:01 UTC,
    updated_at: 2015-06-23 06:45:57 UTC, last_name: "Foo", cv_pdf: ""> 
2.0.0-p353 :016 > f = File.open("test1.pdf")
    => #<File:test1.pdf> 
2.0.0-p353 :017 > c.cv_pdf = f
    => #<File:test1.pdf> 
2.0.0-p353 :019 > c.save
  NoMethodError: undefined method `__bson_dump__' for #<File:test1.pdf> 
  [...]
2

There are 2 answers

1
ifyouseewendy On

Use ahoward/mongoid-grid_fs gem, and save the GridFS file id instead. Write a setter and getter helper to make it easy handle.

class Client
  field :cv_pdf_id, :type => String

  def set_cv_pdf(file_path)
    self.cv_pdf_id = Mongoid::GridFs.put( File.open(file_path) ).id
    self.save
  end

  def get_cv_pdf
    Mongoid::GridFs.get(cv_pdf_id)
  end
end

# Write
c = Client.new
c.set_cv_pdf('test1.pdf')

# Read
c.cv_pdf      # => #<Mongoid::GridFs::Fs::File:0x007fed8d8b6230>
c.cv_pdf.data # => Blob data
0
mu is too short On

Your problem is that you're trying to store a File instance in MongoDB:

f = File.open("test1.pdf")
c.cv_pdf = f

but Mongoid/Moped/MongoDB know what to do with a File. That's what a NoMethodError error complaining about a missing __bson_dump__ method means: you're giving Mongoid something that it doesn't know how to translate into MongoDB-compatible data.

The solution is pretty straight forward: read the file and give its content to Mongoid:

c.cv_pdf = File.read('test1.pdf', :mode => 'rb')