Rails Gem开发(一)——Carrierwave 实现文件上传

来源:互联网 发布:淘宝虚拟市场清退标准 编辑:程序博客网 时间:2024/06/04 01:15

按照项目需求,需要实现从本地上传文件到rails服务器的功能。我们选择使用carrierwave来实现这一功能。

github:https://github.com/carrierwaveuploader/carrierwave

开发前需要明确的问题

在开发时,我们不能盲目的去实现功能。为此,在实践之前,我们需要提出一些问题来引导我们解决问题:

  • 整个文件上传的流程是怎样的?
  • carrierwave 扮演了流程中的什么角色?
  • carrierwave 提供了哪些上传文件的接口?
  • 我们需要实现那些功能来完成整个系统?

提出这些问题,是为了让自己能够更深刻地理解整个系统的工作,在整体上把握,而不仅仅是把功能实现。

问题解决

rails文件上传流程

我们需要结合rails 服务器的MVC框架来分析文件上传的整个流程。

我们需要将本地的文件上传到服务器,那么首先我们需要一个界面(view层),这个界面上提供读取本地文件和上传文件的功能。浏览器通过发送http请求来访问服务器,我们需要上传的文件信息也应该存在请求中。

http请求通过路由(routing)选择特定的控制器(controller),执行特定的动作(action)来获取http请求中的文件信息,获取到信息后我们即可执行将文件存储到特定位置的操作了,但MVC框架告诉我们不应该这么做,数据逻辑和业务逻辑都应该放在model中执行。

我们还需要一个model来进行业务逻辑的实现,获得的信息我们既可以存到数据库中,也可以存到服务器的任意位置。这里,我们需要将文件存储到服务器的特定位置,而不需要存储到数据库中。因此,我们的model实际是不需要对应table(表)的,只需要在model层实现存储文件于特定位置的功能即可。

carrierwave 在流程中的实现

理解了rails服务器中文件上传的流程,我们再来看看carrierwave能为我们实现什么功能。我们来看github中的描述:

Getting Started

Start off by generating an uploader:

rails generate uploader Avatar

this should give you a file in:

app/uploaders/avatar_uploader.rb

从中我们可以看到,carrierwave为我们实现的是model层的功能,也就是实现的是将文件存储到rails服务器中的功能。

carrierwave 提供的部分重要接口

  • 文件存储接口:
uploader = AvatarUploader.newuploader.store!(my_file)
  • 文件存储位置接口:
class Avatar < CarrierWave::Uploader::Base    def store_dir        'public/my/upload/directory'    endend
  • 临时文件存储位置接口:
class Avatar < CarrierWave::Uploader::Base    def cache_dir        '/tmp/projectname-cache'    endend
  • 文件格式白名单接口(不设置时允许所有类型格式的文件):
class Avatar < CarrierWave::Uploader::Base    def extension_whitelist        %w(jpg jpeg gif png)    endend

我们需要实现的功能

根据上面的分析,我们发现carrierwave已经帮我们实现了model层的内容,并为我们提供了重要的接口,我们需要做的就是实现view层和controller层的功能,使上传文件的整个系统能够正常运行。下面,我们就来完成整个系统。
上传文件系统开发流程

我们会用一个非常简单的demo来说明上传文件的流程,这个demo实现了上传文件的最基本的功能,虽然很简单,但每一步都是不可或缺的,缺少任何一个部分,都会导致上传文件的失败。

1. 安装carrierwave(Gemfile.rb

gem 'carrierwave', '>= 1.0.0.beta', '< 2.0'

2. 生成uploader(model层)

rails generate uploader Myuploader

生成文件:app/uploaders/myuploader_uploader.rb,在这个文件中定义了存储文件位置等接口。

3. 现在我们需要在view层添加接口

<%= form_tag 'mystore', :multipart => true do%>    <%= file_field_tag :localfile %>    <%= submit_tag "上传"%><% end %>

我们在页面中添加一个最小的接口单元,form_tag 中添加 :multipart => true 即可实现文件上传,否则会导致无法上传。 第一行中 'mystore' 是指提交按钮发送请求(post)的url,这是一个相对路径,具体内容请复习表单内容。

4. 接着我们需要通过controller来连通整个系统。一方面,controller需要获得提交的http请求中包含的有效的文件信息,另一方面,需要将获得的信息送到model中进行处理。在rails的控制器文件中(*_controller.rb)添加:

def mystore    up_file = params[:localfile]    myfile = MyuploaderUploader.new    myfile.store!(up_file)end
注意,`submit_tag` 发送http请求时的方式是post,因此需要在 `routes.rb` 文件中添加post方法。

通过上述四个步骤,我们便已经成功地实现了本地文件上传rails服务器的功能。

如果需要修改文件存储的位置,文件属性等问题,在 app/uploaders/myuploader_uploader.rb 文件中修改对应的参数即可。

其中,给上传文件配置合理文件名是很重要的事情,这里采用根据文件内容进行MD5加密来给文件命名的方法:

def filename    if original_filename        @name ||= Digest::MD5.hexdigest(File.open(current_path, "rb") { |f| "#{f.read}" })        "#{@name}.#{file.extension}"    endend

这样,整个系统最基本的功能便实现了,我们可以愉快地上传文件了。

总结

carrierwave着实让文件上传变得轻松且愉快,虽然写了这么多,但实际需要自己写的东西是十分少的。然而在自己刚开发时,走了很多弯路,总结起来还是太急功近利了,为了实现功能而实现功能,没有很好地理解文件上传流程,也没有从整体上把握,最终自己给自己挖下了很多坑。

这篇blog写了这么多,不仅仅是介绍carrierwave这个gem包的开发,更重要的是为自己总结gem包开发时的思路:把握整体,弄清系统框架,了解gem包实现的功能,明确gem提供的接口,注重细节,才能更有效地去做rails gem开发。

0 0