Gem gem 'carrierwave'简易实用介绍

jesktop · 2012年08月17日 · 最后由 torvaldsdb 回复于 2017年01月20日 · 16536 次阅读

gem 'carrierwave'

Carrierwave 的主要功能是用于上传文件或者图片的 Gem,功能非常强大。我在这里做一个非常简单的使用步骤,并不对 Carrierwave 做详细的介绍。


创建 uploader

$ rails g uploader Photo
   create  app/uploaders/photo_uploader.rb

uploader 这个文件非常重要,carrierwave 许多功能都将在 photo_uploader.rb 里实现。

创建字段存储文件信息

$ rails g migration AddPhotoToUsers photo:string 
      invoke  active_record
      create    db/migrate/20120816163431_add_photo_to_users.rb

photo 字段使用与存储上传文件的地址字段。 然后在 User 的 model 中加入调用 carrierwave 的信息:

class User < ActiveRecord::Base
  mount_uploader :photo, PhotoUploader

这样 Model 和数据库就可以处理好上传上来的文件了。 接下来需要处理一下 View,在正常的 new 下添加上传的按钮。

Views 中添加相关设置

<%= form_for @user, :html => {:multipart => true} do |f| %>
  <p>
    <label>My Photo</label>
    <%= f.file_field :photo %>
    <%= f.hidden_field :photo_cache %>
  </p>
<% end %>

关键在 form_for 中添加:html => {:multipart => true},就可以使用上传功能了。

使用只需要在需要的地方添加<%= image_tag(@user.photo_url) %>就可以了。 这样,就完成了上传功能了。下面对上传图片的一些特别事项,做一些简单的描述。


使用 RMagick 生成多个图片版本

这里需要使用到另外一个 Gem,名字为 RMagick。 如果在安装 gem 'rmagick'的过程中出现“Can't find Magick-config”的错误,以下链接就有处理这个问题的方法。 http://stackoverflow.com/questions/5201689/rmagick-gem-install-cant-find-magick-config 安装完 RMagick 后,就可以设置版本信息。 打开 class PhotoUploader,然后添加 RMagick 支持:

include CarrierWave::RMagick

注意:由于 RMagick 会导致内存泄露,建议使用 Mini_Magick,gem "mini_magick",使用方法基本和 RMagick 差不多

include CarrierWave::MiniMagick

设置版本信息:

process :resize_to_fit => [800, 800]       #图片大小不超过800*800

version :thumb do                                 #版本名为thumb
  process :resize_to_fill => [200,200]      #想图片处理成200*200大小
end
  • 不设置 vesrion 则为默认版本,既使用方法为<%= image_tag(@user.photo_url) %>
  • 而 thumb 版本的使用方法也很简单,<%= image_tag(@user.photo_url(:thumb)) %>也就是添加 thumb 参数就可以了,版本号为什么就添加什么。非常方便。 # 限制文件上传格式 # 添加如下代码就可以让用户只上传图片文件了。 ruby class PhotoUploader < CarrierWave::Uploader::Base def extension_white_list %w(jpg jpeg gif png) end end * * * 这是个非常简单的教程,也谈不上是教程,也就是说明书而已,因为在 github 上,我说写的上面的写的非常清楚。我就是抽出一部分我比较常用的内容写了下来,这样就可以直接按照上面的流程下来,完成需要的部分功能。 如需要了解更加详细的内容,可以登陆:https://github.com/jnicklas/carrierwave

如何实现图片预览和用户自定义剪裁呢?可否给个思路 谢谢楼主了

楼主,这句话的作用是什么呢? <%= f.hidden_field :photo_cache %>

顺便问一下楼主 photo_cache 是什么

楼主,请使用 Mini_Magick 替换 RMagick,那个有内存泄漏问题

#1 楼 @karma 剪裁预览用 Jcrop

预览和用户自定义剪裁都是用 js 实现的

@fresh_fish @metal 谢谢,我去了解一下 jcrop! 还有一个问题,我也听说过 RMagick 有内存泄露的问题所以我平时使用的时候都是使用的 Mini_Magick,但是 Mini_Magick 只能处理已存在的图片吗?我在做一个验证码生成的 gem 时候遇到了这样的问题: 我希望直接将内存中的图片(验证码)输出给用户,而不写入到服务器上,RMagick 好像可以实现,Mini_Magick 要怎么做呢? 如果做验证码的话,是一次性生成还是,然后随机抽取给用户;还是用户请求的时候再动态生成比较好呢?效率上,和安全上那种好一些呢? 如果一次性生成的话,有必要对这些图片 cache 吗?

最后,如何模拟大量的请求呢?对于商业的项目在开发时有没有特别要注意的地方,我问的比较笼统,因为自己对这方面的积累几乎完全空白,所以有没有相关的书或者 rails 的开源项目推荐,最好能有一些书,因为看项目的话,很多时候不能知其所以然,我希望能补充一些理论方面知识?

谢谢了!

#8 楼 @karma Mini_Magick 可以直接调用 ImageMagick 的命令,所以 RMagick 能做的 Mini_Magick 一样能做,但是你得先了解一下 ImageMagick 的 命令。 模拟大量请求 可以用 Apache ab 模拟并发吧

#2 楼 @tomwey #4 楼 @metal 官方解释是:Often you'll notice that uploaded files disappear when a validation fails. CarrierWave has a feature that makes it easy to remember the uploaded file even in that case. 实际上使用的效果是这样的,就是当你选择了文件之后,然后把你的文件仿如 cache 中。 例如:如果你的表单有 name,photo(上传图片),而表单验证的要求是,必须 name 是不可以空白或者带有文字,然后这时候,你填写了 name 为 123,而 photo 也上传了图片,然后提交,却无法通过验证。这个适合 cache 的作用就出来了。 当有这行代码<%= f.hidden_field :photo_cache %>则在验证返回之后,你不需要在重新上传图片,只需要把 name 改为 abc 就可以成功的提交表单了。 而如果没有的话,就会因为图片没有存在 cache 中也没有上传到服务器里,所以当 name 的验证失败返回后,就需要你重新在上传一次图片了。

#5 楼 @fresh_fish Thanks,一直还不知道 RMagick 有这样的问题。

#1 楼 @karma 自定义剪切仅仅靠这些个 gem 是不行的,js 有很多自定义剪切图片的插件,google 一下很多的,具体怎么处理可见其 demo

匿名 #13 2012年08月18日

js 剪切图片???貌似常用的是 js 获取选择的两个点的元素坐标,把坐标和图片信息发到服务器,然后再服务器用 Mini_Magick 来剪吧。

不过 html5 或许有支持,这个偶不知道。

为什么我文件裁剪,最后没保存进去!

class AvatarUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :upyun

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    # "uploads/#{model.class.to_s.underscore}/#{model.id}"
    "#{model.class.to_s.underscore}/#{mounted_as}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  def default_url
    _filename = ["default_avatar", version_name, "png"].join(".")
    # For Rails 3.1+ asset pipeline compatibility:
    return ActionController::Base.helpers.asset_path("fallback/#{_filename}")

    "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  end

  # Process files as they are uploaded:
  # process :scale => [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:

  process :cropper

  version :thumb do
    process resize_to_fit: [50, 50]
  end

  version :mid do
    process resize_to_fit: [180, 180]
  end

  version :large do
    process resize_to_fit: [300, 300]
  end

  def cropper
    if model.crop_x.present?
      manipulate! do |img|
        x = model.crop_x
        y = model.crop_y
        w = model.crop_w
        h = model.crop_h
        img.crop "#{w}x#{h}+#{x}+#{y}"
      end
    end
  end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_white_list
    %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  def filename
    "#{secure_token}.#{file.extension}" if original_filename.present?
  end

  protected
  def secure_token(length=16)
    var = :"@#{mounted_as}_secure_token"
    model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.hex(length/2))
  end
end

怎么修改图片的名字,名字是 uuid 自动生成的。

@JeskTop 楼主你好,请问下你是怎么实现多文件上传的?因数用 carrierwave 要数据库支持 array 或者 json 数据类型,但 mysql 是不支持的,文档如下:

Add a column which can store an array. This could be an array column or a JSON column for example. Your choice depends on what your database supports. For example, create a migration like this:

rails g migration add_avatars_to_users avatars:json rake db:migrate Open your model file and mount the uploader:

class User < ActiveRecord::Base mount_uploaders :avatars, AvatarUploader end Make sure your file input fields are set up as multiple file fields. For example in Rails you'll want to do something like this:

<%= form.file_field :files, multiple: true %> 多谢

#17 楼 @luolinae86 不好意思,目前我也还没有做过多图上传的。

#16 楼 @liker CarrierWave 里 有个自带的 filename 方法,可以定义存到文件夹里面 文件的名字。文件的原来的名字是 original_filename

#17 楼 @luolinae86 同求怎样实现多文件上传,数据也是 MySQL

@15731118085 多文件及图片上传的,我最终是用的 jquery 文件异步上传插件,非常好用,也没用阻塞服务,请参考下面的例子

https://blueimp.github.io/jQuery-File-Upload/

你好,我在显示图片时遇到如下问题: wrong number of arguments (given 1, expected 0)

Extracted source (around line #18):

<%= @course.course_introduction %> 18 <%= image_tag(@course.avatar(:lb)) %>

Rails.root: /home/stormand/RubymineProjects/CourseSelect Application Trace | Framework Trace | Full Trace

app/views/courses/detail.erb:18:in `app_views_courses_detail_erb_3528013227028476933_69855157661360'

Request

Parameters:

{"id"=>"1"}

为什么添加 (:lb) 版本号后就会报错啊?如果删去 (:lb) 就没有问题。 uploader 中也定义了版本

#22 楼 @stormand 这个 4 年前的文章了啊,现在 gem 更新了什么,有什么改动,你要对照文档去操作比较好。

<%= f.hidden_field :photo_cache %>I tried, but it didn't work!

#22 楼 @stormand 如果是版本你的image_tag(@course.avatar(:lb))有点问题吧,image_tag尽管提到

Returns an HTML image tag for the source. The source can be a full path or a file.

但是carrierwave的版本只支持 full path, 你可以尝试image_tag(@course.avatar_url(:lb))或者image_tag(@course.avatar.thumb.url)

需要 登录 后方可回复, 如果你还没有账号请 注册新账号