最近抽空玩了一下Ruby on Rails,用MongoDB来做主数据库,各种Gem功能集合起来还真有些眼花缭乱,决定在博客中把其中较为麻烦的过程记录下来备忘并巩固一下,也为来访者提供一点可用信息。关于环境搭建,如果你用的ubuntu,可以参考我之前在wiki中记录的《Ubuntu下搭建ROR+MongoDB+Redis环境》。

创建应用Demo: (确保mongodb服务已经启动)

$ rails new demo
$ cd demo

修改Gemfile文件,加入如下Gems (gem后面的注释表示当前版本):

gem 'mongoid' # 2.3.4
gem 'bson_ext' # 1.5.2
gem 'carrierwave' # 0.5.8, 实现文件上传功能
gem 'carrierwave-mongoid', :require => 'carrierwave/mongoid' # 0.1.3, 扩展功能,实现存储文件到GridFS

生成mongoid配置文件:

$ rails g mongoid:config

修改 config/application.rb,注释掉require ‘rails/all’,并添加以下内容:

# require 'rails/all'
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "rails/test_unit/railtie"

继续添加以下代码,防止 error mongoid [not found] 的问题

config.generators do |g|
  g.orm :active_record
end

删除 config/database.yml,并用scaffold创建blog应用:

$ rm config/database.yml
$ rails g scaffold blog name:string content:text

到此已经成功一半了,MongoDB已经可以正常工作,运行应用测试一下:

$ rails s

到浏览器输入http://localhost:3000/blogs测试功能。

下面继续添加上传文件到GridFS功能。

添加carrierwave配置文件 config/initializers/carrierwave.rb,内容如下:

CarrierWave.configure do |config|
  config.storage = :grid_fs # 存储类型
  config.grid_fs_access_url = "" # 访问前缀,留空即可
  config.grid_fs_database = Mongoid.database.name # GridFS数据库名
  config.grid_fs_host = Mongoid.config.master.connection.host # GridFS服务器地址
end

生成Uploader:

$ rails g uploader File

修改 app/uploaders/file_uploader.rb 内容为:

# encoding: utf-8
class FileUploader < CarrierWave::Uploader::Base
  # 这里设置存储类类型
  storage :grid_fs
  def store_dir
    # 这里我把上传路径改成简单一些的
    "uploads/#{model.id}" 
  end
end

生成gridfs的controller,方便在开发环境中使用GridFS:

$ rails g controller gridfs

修改内容如下:

class GridfsController < ActionController::Metal
  def serve
    gridfs_path = env["PATH_INFO"].gsub("/uploads/", "uploads/")
    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 Exception => e
      self.status = :file_not_found
      Rails.logger.debug { "#{e}" }
      self.content_type = 'text/plain'
      self.response_body = ''
      raise e
    end
  end
end

修改routes.rb,使开发模式下,通过gridfs这个controller来管理文件,添加代码如下:

if Rails.env.development?
  match "/uploads/*path" => "gridfs#serve"
end

修改app/models/blog.rb,添加file字段,并挂载uploader,最终内容如下:

class Blog
  include Mongoid::Document
  field :name
  field :content
  field :file
  mount_uploader :file, FileUploader
end

修改 app/views/blogs/_form.html.erb,在content表单项下面添加文件上传表单项:

<div class="field">
<%= f.label :file %><br />
<%= f.file_field :file %>
</div>

修改 app/views/blogs/index.html.erb,同样在content单元格后面添加显示文件下载链接的单元格:

<td><%= link_to "Download", blog.file_url %></td>

同样 app/views/blogs/show.html.erb 也是在content后面添加文件下载链接:

<p>
<b>Content:</b>
<%= link_to "Download", @blog.file_url %>
</p>

好了,大功告成,下面可以再次启动应用,到http://localhost:3000/blogs下测试上传功能了。

可能遇到的问题:

  • undefined method `mount_uploader’ for Blog:Class
    这是因为Gemfile中的gem ‘carrierwave-mongoid’后面没有加 , :require => ‘carrierwave/mongoid’

  • 在执行rails命令时,遇到 error mongoid [not found]
    解决方法是在 config/application.rb 文件中,加入:

config.generators do |g|
  g.orm :active_record
end