Mongoid試してみた
特に目先の目的はないんだけど、スキーマとデータを後から自由に、しかもメンテナンスストップせずに変更できそうな気がして MongoDB を動かしてみようと思い、Mongoid をちょっと触ってみた。
自分用のメモなので特に面白い話はないです、念のため。
Mongoidを使った開発の準備
MongoDBのインストール
省略
新規アプリ作成
rspec を使いたいので
rails new APP_NAME -T -O
で、作成。
できあがったアプリケーションのGemfile
assets とか省略して最低限こんな感じ。
gem 'mongoid'
gem 'bson_ext'
group :development, :test do
gem 'rspec-rails'
end
で、これを
bundle instal
します。bson_ext はなくても動くみたいだけど、なんかいろいろメッセージが出てうるさかったのでインストールして黙らせた。
generatorを叩いて設定ファイル作成
mongoid のインストールが成功していれば
rails g mongoid:config
これで config/mongoid.yml ができる。これは中身いじらなくて ok. rspec の分は省略。
dbの場所確保とmongod起動task
MongoDB は SQLite3 のような組み込み用ではないので daemon を起こす必要がある。繊細な感じがしていやだったので以下のような rake task を用意した。
# -*- mode: ruby -*- | |
include FileUtils::Verbose | |
@root = File.expand_path( File.dirname(__FILE__) + '/../../' ) | |
namespace :mongo do | |
desc 'prepare' | |
task :prepare do | |
dbpath = "#{@root}/db/mongodb" | |
mkdir( dbpath ) unless File.exist? dbpath | |
conf = File.join( @root, 'config', 'mongo_develop.conf.erb' ) | |
if ( not File.exist? conf ) | |
open( conf, 'w' ) { |f| | |
f.puts <<'EOD' | |
<% root = File.expand_path( File.dirname(__FILE__) + '/../' ) %> | |
dbpath = <%= "#{root}/db/mongodb" %> | |
logpath = <%= "#{root}/log/mongodb.log" %> | |
EOD | |
} | |
puts "created #{conf} ." | |
end | |
end | |
desc 'start mongod' | |
task :start do | |
conf = File.join( @root, 'config', 'mongo_develop.conf' ) | |
sh <<EOD | |
bundle exec erubis #{conf}.erb > #{conf} | |
mongod -f #{conf} | |
EOD | |
end | |
end |
これは
db/mongodb/
config/mongo_develop.conf.erb
を作って、conf.erb の内容から conf を生成してこの conf を mongod -f に与えて起動するようになっている。
screen を起こして一つの window で mongod を、もう一つで rails server を起こすようにすると邪魔じゃないしタブの意図が明確になっていいんじゃないかと思う。mongoid.yml の配置以降は mongod 起きてないと rails コマンドがちゃんと機能しないかも。
少なくとも migration は migration 実行時に初めて DB に変更が加わるんだけど Mongoid の場合はその場で変更できるものは変更するらしい。したがって mongod が起きてないと generate や destroy は実行できない。
Modelの作り方
普通に generator を使う。上のセットアップを済ますと generate model は Mongoid の model 生成用 generator に差し替わっている。1
できるのはこんなモデル。
class Foo
include Mongoid::Document
end
ただし、これだと timestamps 相当の field がない。ActiveRecord::Migration が標準で作るのと同じ感じの Model にするには以下のように作る。
class Bar
include Mongoid::Document
include Mongoid::Timestamps
field FIELD_NAME, { option }
end
Mongoid はこんな感じで便利機能をイロイロ include できるらしいので一度確認しておくとよさげ。
Mongoid + Dragonfly
ActiveRecord の場合は以前
今さらRails3メモ - 番外編その1: Paperclip and Dragonfly
で書いたように require するだけでいいんだけど、Mongoid の場合はもう一手間必要。
File: Mongo — Documentation by YARD 0.7.4
と言っても本家に書いてある通りで、
require 'dragonfly'
app = Dragonfly[:images]
...
# Allow all mongoid models to use the macro 'image_accessor'
app.define_macro_on_include(Mongoid::Document, :image_accessor)
MongoDataStore 使わないなら上の実質2行を initializer に加えるだけ。
感想
migration がないので最初のセットアップのテンポがいい。ActiveRecord のときは
- migration の方に column を書く
- Model に attr_accesible 定義や validation で column を書く
- さらに管理画面に Typus を使ってると Typus で編集可能な column 定義書く
という感じで、
DRY !!!
って叫びたくなる。それが Mongoid + RailsAdmin だとだいぶ楽ちんな感じ。2
とは言え migration がないので逆に field 名変更は全 document に対して実行しなければいけない。rails runner でのバッチ処理の出番か。
もともとできるだけ生SQLは書かないようにしていた3し、別に RDBMS 脳でもないので Mongoid 縛りで MongoDB を使うのにはそれほど抵抗ないんじゃないかなーと思っている。まだ Relation 使ってないから join ねーよ!ってときの気持ちが分からないけど、ま、なんとかなるんじゃないかな?