Carrierwave + Mongoid + gridfs + Padrino admin image upload

爷,独闯天下 提交于 2019-12-11 02:49:44

问题


i'm trying to get carrierwave + mongoid + gridfs to work for uploading images via padrino admin and then showing on front-end. at a loss as to glue everything. can someone help?

following https://blog.engineyard.com/2011/a-gentle-introduction-to-carrierwave/ and https://github.com/carrierwaveuploader/carrierwave-mongoid.

trying to persist an "Artwork" with an image upload returns:

NoMethodError at /admin/artworks/update/53a0eedcf2c7961066000002 undefined method `bson_dump' for # file: hash.rb location: block in bson_dump line: 15

mongofiles -d database list

returning empty.

question is: what's wrong with the code at the moment?

uploader: https://github.com/bcsantos/debug/blob/master/lib/uploader.rb

class Uploader < CarrierWave::Uploader::Base

  ##
  # Image manipulator library:
  #
  include CarrierWave::RMagick
  # include CarrierWave::ImageScience
  # include CarrierWave::MiniMagick

  ##
  # Storage type
  #
  storage :grid_fs
  # configure do |config|
  #   config.fog_credentials = {
  #     :provider              => 'XXX',
  #     :aws_access_key_id     => 'YOUR_ACCESS_KEY',
  #     :aws_secret_access_key => 'YOUR_SECRET_KEY'
  #   }
  #   config.fog_directory = 'YOUR_BUCKET'
  # end
  # storage :fog

resize_to_limit(1024, 768)

  ## Manually set root
  def root; File.join(Padrino.root,"public/"); end

  ##
  # Directory where uploaded files will be stored (default is /public/uploads)
  #
  def store_dir
    'content'
  end

  ##
  # Directory where uploaded temp files will be stored (default is [root]/tmp)
  #
  def cache_dir
    Padrino.root("tmp")
  end

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

  ##
  # Process files as they are uploaded.
  #
  # process :resize_to_fit => [740, 580]

  ##
  # Create different versions of your uploaded files
  #
  # version :header do
  #   process :resize_to_fill => [940, 250]
  #   version :thumb do
  #     process :resize_to_fill => [230, 85]
  #   end
  # end
  ##
  # White list of extensions which are allowed to be uploaded:
  #
  def extension_white_list
    %w(jpg jpeg gif png)
  end

  ##
  # Override the filename of the uploaded files
  #
  # def filename
  #   "something.jpg" if original_filename
  # end
end

-----------

upload https://github.com/bcsantos/debug/blob/master/app/models/upload.rb

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

  # field <name>, :type => <type>, :default => <value>
  field :file, :type => String
  field :created_at, :type => Time

  attr_accessible :upload

  mount_uploader :upload, Uploader


  # You can define indexes on documents using the index macro:
  # index :field <, :unique => true>

  # You can create a composite key in mongoid to replace the default id using the key macro:
  # key :field <, :another_field, :one_more ....>
end

-----------

model i want to associate the upload/picture with https://github.com/bcsantos/debug/blob/master/app/models/artwork.rb

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

  # field <name>, :type => <type>, :default => <value>
  field :name, :type => String
  field :year, :type => Integer
  field :author, :type => String
  field :rent_price, :type => String
  field :sale_price, :type => String
  field :medium, :type => String
  field :size, :type => String
  field :colour, :type => String

  field :picture, :type => Upload
  field :thumbnail, :type => Upload


  # You can define indexes on documents using the index macro:
  # index :field <, :unique => true>

  # You can create a composite key in mongoid to replace the default id using the key macro:
  # key :field <, :another_field, :one_more ....>
end

-----------

controller to retrieve files from database (thanks @Darío)

TourApart::App.controllers do

  get :gridfs, map: '/content/*' do
    gridfs_file = Mongoid::GridFS[params[:splat]]
    content_type gridfs_file.content_type
    gridfs_file.data
  end

  error Mongoid::Errors::MongoidError do
    halt 404, 'File not found'
  end

end

回答1:


First, given this model design, your Artwork model isn't properly embedding the Upload document. It should instead embed the picture and thumbnail field like so:

class Artwork
  # ...
  embeds_one :picture, class_name: "Upload"
  embeds_one :thumbnail, class_name: "Upload"
  # ...
end

Aside, I don't understand why you have an Upload document in the first place. It seems unnecessary given your design. The Uploader holds all the information that you're trying to store in your Upload model. For example, your Artwork model could instead just look like this (and you can dump the Upload model all together):

class Artwork
  # ...
  mount_uploader :picture, Uploader
  mount_uploader :thumbnail, Uploader
  # ...
end

Your picture and thumbnail field will hold things like the date it was updated, the filename, the file date, etc.

Also, it looks like you're trying to manually manage the thumbnail. I presume the thumbnail is a smaller version of the picture. Carrierwave can handle this for you too:

class Artwork
  # ...
  mount_uploader :picture, Uploader
  # ...
end

Then add something like this to your Uploader:

class Uploader < CarrierWave::Uploader::Base
  # ...
  version :thumbnail do
    process resize_to_fill: [160, 120]
  end
  # ...
end

That way, you'll have a Artwork#picture and a Artwork#picture_thumbnail accessor for the two different versions.

More examples:

  • Artwork#picture.read - get the image data
  • Artwork#picture.file - get the image file
  • Artwork#picture_thumbnail.file - get the thumbnail version's file
  • Artwork#picture.file.content_type - yup, the content_type
  • etc

Lastly, if you're using carrierwave-mongoid, there's no need to access Mongoid::GridFS directly in your controller. Look-up the artwork and just access the picture field. Let GridFS stay behind the scenes.

Aside, I would recommend using CarrierWave::MiniMagick over CarrierWave::RMagick. It just makes things easier in the long run, IMO, but it requires that you have ImageMagick installed on your machine.




回答2:


This took a while... to help others save time, here goes:

gemfile

#...
gem 'mongoid', '~>3.0.0'
gem 'carrierwave-mongoid', :require => 'carrierwave/mongoid'
gem 'mini_magick', :require => 'mini_magick'
#...

lib/uploader.rb

class Uploader < CarrierWave::Uploader::Base

  include CarrierWave::MiniMagick

  storage :grid_fs

  ##
  # Directory where uploaded files will be stored (default is /public/uploads)
  #
  def store_dir
    '/content/images'
  end

  ##
  # Directory where uploaded temp files will be stored (default is [root]/tmp)
  #
  def cache_dir
    Padrino.root("/tmp")
  end

  def extension_white_list
    %w(jpg jpeg gif png)
  end

  ##
  # Override the filename of the uploaded files
  #
  # def filename
  #   "something.jpg" if original_filename
  # end
end

model

class Thing
  include Mongoid::Document
  include Mongoid::Timestamps

  field :name, :type => String
  field :year, :type => Integer
  #...

  mount_uploader :picture, Uploader
end

controller

YourApp::App.controllers :things do

  get :image, with: [:id], provides: ['.jpeg', '.jpg', '.png', '.gif'] do
    thing = Thing.find(params[:id])
    content_type thing.picture.content_type
    response.write(thing.picture.read)

  end

  error Mongoid::Errors::MongoidError do
    halt 404, 'File not found'
  end

end

view (haml)

/...
%img{:src => url_for(:things, :image, thing.id)}/
/...

admin/views/things/_form.haml

/...
%fieldset.control-group{:class => error ? 'has-error' : ''}
  =f.label :picture, :class => 'control-label'
  .controls
    =f.file_field :picture, :class => 'form-control input-large input-with-feedback'
    %span.help-inline=error ? f.error_message_on(:picture, :class => 'file-error') : pat(:example)
/...

Thanks @Ryan McGeary and @Darío.



来源:https://stackoverflow.com/questions/24203977/carrierwave-mongoid-gridfs-padrino-admin-image-upload

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!