LoginSignup
26
25

More than 5 years have passed since last update.

RailsでActiveRecordとMongoidの共存のさせ方

Last updated at Posted at 2013-02-13

背景

Herokuで適当にスキーマレスなデータをOutput出来る場所がほしい!でも、Herokuはディスクが自由に使えないので、text書き出しができない!!
こんな要求の解決法としては、textタイプのフィールドを作ってserializestoreを使うのが一つの手。ただ、割と書き込みが多い事が想定され、無駄に大切なPostgreSQLサーバーに負荷をかけてしまう。
そんなこんなでスキーマレスな出力場所としてMongoDBを使うというアイデアが持ち上がった。HerokuではMongoHQなら16M、MongoLabなら0.5Gが無料で使える。
なお、基本的に、MongoDBをサブとして使うのでrails g modelなどをした時にmongoidがinvokeされるのは避けたい。

実践

gem 'mongoid'

して、bundle install

$ rails generate mongoid:config

すると、config/mongoid.ymlにdevelopmentとtestの設定が生成されるので、ここにconfigurationを書く。基本的には変更する必要がないが、database, username, passwordあたりの書き換え、書き足しだけチェックしてみればいいのではないだろうか?

productionの設定はHerokuのAdd-onのドキュメント通りにすれば良いと思う。MongoHQのドキュメントの方が詳しく書かれていたのでこっちを参照した。使ったのはMongoLabだけど(笑)

ちゃんと設定したければ、
http://mongoid.org/en/mongoid/docs/installation.html
にそれぞれオプションが詳しく載っている。

mongoidのモデルはrails generate modelでできるようになっている。

$ rails generate model user_mongo name:string
    invoke  mongoid
    create    app/models/user_mongo.rb
app/models/user_mongo.rb
class UserMongo
  include Mongoid::Document
  field :name, type: String
end

ということは、ActiveRecordのmodelを作るとき、active_record:とprefixをつける必要がある。

$ rails generate acrive_record:model

これはmigrationコマンドやgemのdeviseなどでも同様。

これが困る場合、application.rb

config/application.rb
config.generators do |g|
  g.orm :active_record
end

と追加すれば良い。このときmongoidのモデルを作るときは

$ rails generate mongoid:model

とする。

最後に、Mongoidの使い方は、適当に自分で調べて使ってみれば意外と簡単に使えると思うが、http://mongoid.org/en/mongoid/docs/relations.html は読んでおくと良いと思う。多分ActiveRecordとはちょっと違っていて難しいであろう、Relation/Associationのあたりの話がちゃんと書いてある。

参考

追記: ロードするclassの設定

mongoidのgemを見ると設定なしではapps/model以下の全てのRubyファイルをロードしてしまう設定になっていた。

これを防ぐためには、optionspreload_modelsにMongoid::DocumentをIncludeしているクラスを全て指定すれば良い。
例えば、data_mongo.rbuser_monbo.rbを作った場合は、

mongoid.yml
production:
  # ...
  options:
    preload_models:
      - data_mongo
      - user_mongo

というように設定する。

一応、今後解決する可能性もあるので、mongoidの問題となっている部分のを載せておく

mongoid3.0.22/lib/rails/mongoid.rb
    def load_models(app)
      app.config.paths["app/models"].each do |path|
        preload = ::Mongoid.preload_models
        if preload.resizable?
          files = preload.map { |model| "#{path}/#{model}.rb" }
        else
            files = Dir.glob("#{path}/**/*.rb")
        end

        files.sort.each do |file|
          load_model(file.gsub("#{path}/" , "").gsub(".rb", ""))
        end
      end
    end
26
25
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
25