之前我们已经聊过 MongoDB 的安装和 Ruby on Rails 项目的搭建,那么接下来自然就是——怎么把这两者整合到一起,真正跑起来。下面就把整个流程拆解一下,其实不算复杂,跟着走一遍就能搭出一个可用的环境。
1. 创建项目
创建 Rails 项目时,需要明确去掉默认的 ActiveRecord 支持,因为我们要用 MongoDB 做数据层。命令很简单:
```bash
rails new todo -O
```
`-O` 参数就是告诉 Rails 别带 ActiveRecord 那一套,干干净净,后面再单独接 MongoDB。
2. 引入 MongoMapper 驱动
Rails 连接 MongoDB 有很多种方式,这里我们选 **MongoMapper**,它对 Rails 的集成做得很顺手。先在 `Gemfile` 里加上一行:
```ruby
gem "mongo_mapper"
```
然后执行 `bundle install` 把依赖装上:
```bash
bundle install
```
这一步没什么坑,等它装完就行。
3. 配置数据库连接
在 `config/initializer` 目录下新建一个 `mongo.rb` 文件,用来定义全局的数据库连接信息。内容如下:
```ruby
MongoMapper.connection = Mongo::Connection.new('localhost', 27017)
MongoMapper.database = 'todo'
```
这里需要留意:如果项目在不同环境(开发、测试、生产)下需要隔离数据,可以通过 Rails 的运行环境参数来指定不同的数据库名称。当然,为了快速验证,我们只写了一个 `todo` 库,后续按需调整即可。
另外,如果部署环境是 **Phusion Passenger**,还需要加上一段处理进程分叉后的连接重连逻辑:
```ruby
if defined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do |forked|
MongoMapper.connection.connect if forked
end
end
```
完成这些配置后,启动 Rails
服务器试试:
```bash
$ rails server
```
首次启动时,可能会看到一行提示:
```
**Notice: C extension not loaded. This is required for optimum MongoDB Ruby driver performance.
You can install the extension as follows:
gem install bson_ext
```
这是正常的——bson_ext 这个 C 扩展没有安装,会影响性能,但不影响功能。按提示把它装一下,同时在 `Gemfile` 里加上 `gem "bson_ext"` 并重新 `bundle install`,然后再启动,那个 Notice 就会消失,
服务器正常跑起来。在浏览器访问 `http://127.0.0.1:3000`,就能看到 Rails 欢迎页面了。
4. 添加页面和业务逻辑
接下来要生成模型、控制器和视图。Rails 自带的 `scaffold` 命令可以快速出整套 CRUD,我们只需要指定 ORM 为 `mongo_mapper` 即可:
```bash
rails generate scaffold project name:string --orm=mongo_mapper
```
不过,生成的模型默认还是继承自 `ActiveRecord::Base`,需要手动改一下,让模型继承 `MongoMapper::Document`。同时用 `key` 方法定义字段。比如项目只有一个 `name` 字段,类型是 `String`,那么模型文件就长这样:
```ruby
class Project
include MongoMapper::Document
key :name, String
end
```
改完之后,增删改查的所有操作就已经自动就绪了,不需要额外写任何 SQL 或迁移脚本。
5. 数据验证与查看
MongoDB 是 schemaless 的,所以添加或修改字段非常灵活。比如想加一个 `priority` 字段,只需要在模型里加一行:
```ruby
class Project
include MongoMapper::Document
key :name, String, :required => true
key :priority, Integer
end
```
不需要跑任何 migration,直接重启
服务器就生效。验证逻辑也完全兼容 ActiveRecord 的写法,比如 `validates_presence_of :name` 照用不误。
至于表之间的关联,MongoMapper 也提供了与 ActiveRecord 类似的语法。比如一个 Project 有多个 Tasks,只需在 Project 模型中定义 `many :tasks`,在 Task 模型中定义 `belongs_to :project`,不过内部存储用的是 `ObjectId` 类型来关联 ID。
数据查看也很直接,进入 MongoDB 命令行:
```bash
mongo
use todo
db.projects.find()
```
就能看到刚插入的数据。
6. 附录:用 Ruby 写一个 MongoDB 备份脚本(fsync & lock)
最后附上一个实用的备份脚本。它通过 `fsync` 加锁来保证文件系统一致性,然后拷贝数据文件,最后解锁。脚本本身是用 Ruby 配合 `mongo-ruby-driver` 写的,适用于复制集环境。
```ruby
#!/usr/local/bin/ruby
# date: 06-12-2014
# use fsync and lock to the file-system before backup the file-system
# mongo-ruby-driver version > 1.10.0
require 'mongo'
require 'fileutils'
require 'date'
include Mongo
include BSON
uri_string = "mongodb://caoqing:xxxxxxxx@x.x.x.x:27017/admin"
client = MongoClient.from_uri(uri = "#{uri_string}")
db = client['admin']
# fsync and lock the database
cmd = OrderedHash.new
cmd[:fsync] = 1
cmd[:lock] = true
db.command(cmd)
# datafile path
d = "/var/lib/mongo"
start = Date.today.to_s
prev = (Date.today - 7).to_s
dest = "/backup/#{start}"
sour = "/backup/#{prev}"
FileUtils.rm_rf("#{sour}") if File::exist?("#{sour}")
Dir.mkdir("#{dest}", 0755) unless File::exist?("#{dest}")
FileUtils.cp_r Dir.glob("#{d}/**"), dest if client.locked?
puts "*" * 20
puts "tbackup complete"
puts "*" * 20
# unlock the database
db["$cmd.sys.unlock"].find_one
client.close
```
使用时注意替换连接字符串中的地址、用户名和密码,以及数据文件路径和备份目录。脚本会保留最近 7 天的备份,自动清理更早的版本。
到这里,整个整合过程就聊完了。目前就做到这一步,后面有时间再深入探索 MongoDB 在 Rails 中的更多玩法,比如分片、复制集读写分离等等。
本文转载于:https://www.jb51.net/article/87968.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。