2012年11月

mongoid2 を mongoid3 にあげてみた

こんにちは @sonots です。別に旬でもなんでもないのはわかっていますが、mongoid 2.x を 3.x にバージョンアップする作業をしたので、ポイントなどをまとめておこうと思います。

参考にしたもの

まずは参考にしたもの。重要だと実感した順。

  1. mongoid の CHANGELOG
  2. 利用してた 2.x 系バージョンの mongoid のコード
  3. 利用する 3.x 系バージョンの mongoid のコード
  4. ぐーぐる

いつもなら「1. ぐーぐる」なんですが、こういう作業の場合はあまり参考になりませんね。CHANGELOG に変更箇所が載っていると非常に捗りました。CHANGELOG に載ってなくて、コードを直接読まないといけないことも多々ありましたが・・・

というわけで、さっそく。

index の書き方が変わった

class Band
  include Mongoid::Document
  index([[:field1, Mongo::ASCENDING], [:field2,  Mongo::DESCENDING]])
end

のように書いていた index の書き方が

class Band
  include Mongoid::Document
  index({field1: 1, field2: -1})
end

のように変わりました。

Mongo gem に依存しなくなった

Mongo gem を使わなくなったため、Mongo ネームスペースのものが使えなくなっています。

例えば、先ほどでてきた Mongo::ASCENDING は使えなくなったので、mongo 上で直接 index を貼る時と同様に 1 と指定するようになりました。Mongo::DESCENDING は -1 になります、

ほかにも Mongo::Collection が Moped::Collection に変わったりしています。

BSON が Moped::BSON に変わった

BSON::ObjectId が Moped::BSON::ObjectId に変わりました。

BSON::InvalidObjectId エラーが発生しなくなった

Mongoid::Document#find メソッドの引数に _id の型に一致しないオブジェクトを指定すると、BSON::InvalidObjectId エラーが発生していましたが、単に nil が返るようになりました。

補足: find の引数に一致しない要素を持つ Array/Hash を指定した場合は [] が返ります。

collection_name の指定方法が変わった

mongo の collection 名を明示的に指定したい場合は、

class Band
  include Mongoid::Document
  self.collection_name = 'collection_name'
end

と書いていましたが、これが

class Band
  include Mongoid::Document
  store_in collection: 'collection_name'
end

のように変わりました。

mongoid.yml の書き方が変わった

development:
  raise_not_found_error: false
  logger: false
  host: localhost
  port: 27017
  database: mongo_development

のように書いていましたが、

development:
  options:
    raise_not_found_error: false
  sessions:
    default:
      hosts:
        - localhost:27017
      database: mongo_development

のように変わりました。リファレンス を見ると、replica や sharding ができるようになって、hosts を Array で指定するようになったようですね。ホストは port 番号もあわせて指定しなければいけなくなりました。

また、以前は指定できていた mongoid のログ機能をオフにする設定 logger: false が消えました。代わりに

Mongoid.logger = nil

とすることで logger をオフにできるようです。

_id フィールドの型を指定する方法が変わった

_id フィールドはデフォルトで BSON::ObjectId (Moped::BSON::ObjectId) 型になりますが、これを Interger や String 型にしたい場合の指定方法が変わりました。 

class Band
  include Mongoid::Document
  identity type: Interger # field :_id
end

のように書いていましたが、identity マクロが消えました。

class Band
  include Mongoid::Document
  field :_id, type: Interger
end

のように上書きするようになりました。

同時に任意のフィールドを識別子(id)に指定する key マクロも消えました。

class Band
  include Mongoid::Document
  field :name, type: Integer
  key :name
end

のように書いていましたが、

class Band
  include Mongoid::Document
  field :name, type: Integer
  field :_id, type: Integer, default: ->{ name }
end

のように変わりました。CHANGELOG によると、default には proc が指定でき、ほかのすべての field がセットされた"後" に適用されるようです。

セットされる"前"に適用したい場合は、以下のように :pre_processed を true にしろとのことです。

class Band
  include Mongoid::Document
  field :_id,
    type: String,
    pre_processed: true,
    default: ->{ BSON::ObjectId.new.to_s }
end

create(:_id => 1) ができなくなった

これにだいぶハマっていたのですが・・・

上述のように :_id フィールドの型を Integer に変えて直接指定しているコードがあったのですが、create(:_id => 1) としても id に値が設定されず nil のままになります。sensitive_fields という機構が入り、_id および _type に直接値を指定できなくなりました。

mongoid.yml に

develpment:
  options:
    protect_sensitive_fields: false

と指定、または

Mongoid.protect_sensitive_fields = false

とした後に mongoid model をロードすることで、以前と同様に _id および _type に値を直接代入するこができるようになります。

GridFS サポートがなくなった

Mongoid に mongodb の GridFS engine サポートの機能を追加する carrierwave-mongoid を使用していたのですが、現在 rubygems.org にあるものは mongoid 2.x にしか対応していません。

github に mongoid-3.0 ブランチがあったのでそれに移行しようとしていたのですが、こちらの Issue によるとそもそも mongoid 3.x が GridFS をサポートしていないとのことで、GridFS が使えないことが発覚しました。

使わないように別実装に置き換えて対応しました。

まとめ

けっこう大変でしたが、なんとか1日で移行実装を終わらせることができました。と言っても、今日の段階ではテストが通ったというだけなので、また何か追加が必要になるかも。追記します!

protect_sensitive_fields: false の件は、どハマりしていて、create メソッドにあてる monkey patch 書いたり dirty なことをしようとしていたのですが、@shyouhei さんに助けて頂き、clean な解決に辿りつくことができました。大変お世話になっております。謝辞。

(追記) Mongoid2 から Mongoid3 にアップデートするためのオフィシャルな Upgrading ページも用意されていました。親切!

macでruby2.0.0を試してみた

Ruby2.0先取り勉強会a_matsuda さんが Ruby2.0 にすると Rails の起動時間が2倍になるよ!ということを言っていたので試してみた。とはいえ Rails は使っていないので、rspec で速度比較。

インストール

CONFIGURE_OPTS="--with-readline-dir=/usr/local/opt/readline" rbenv install 2.0.0-preview1
rbenv local 2.0.0-preview1
gem install bundler
bundle install

pry-debugger 周りで以下のようにエラーが出た。一旦 Gemfile からオフ。

Installing debugger-linecache (1.1.2) with native extensions 
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

        .rbenv/versions/2.0.0-preview1/bin/ruby extconf.rb 
checking for vm_core.h... no
Makefile creation failed
**************************************************************************
No source for ruby-2.0.0 (revision 37411) provided with debugger-ruby_core_source gem.
**************************************************************************
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=.rbenv/versions/2.0.0-preview1/bin/ruby
        --with-ruby-dir
        --without-ruby-dir
        --with-ruby-include
        --without-ruby-include=${ruby-dir}/include
        --with-ruby-lib
        --without-ruby-lib=${ruby-dir}/


Gem files will remain installed in .rbenv/versions/2.0.0-preview1/lib/ruby/gems/2.0.0/gems/debugger-linecache-1.1.2 for inspection.
Results logged to .rbenv/versions/2.0.0-preview1/lib/ruby/gems/2.0.0/gems/debugger-linecache-1.1.2/ext/trace_nums/gem_make.out
An error occurred while installing debugger-linecache (1.1.2), and Bundler cannot continue.
Make sure that `gem install debugger-linecache -v '1.1.2'` succeeds before bundling.

気を取り直して

bundle install
rspec spec
.rbenv/versions/2.0.0-preview1/lib/ruby/gems/2.0.0/gems/mongo-1.5.2/lib/mongo/util/ssl_socket.rb:1:in `require': cannot load such file -- openssl (LoadError)

1.9.3 の時は大丈夫だったのに mongo gem に openssl がないと怒られた(むしろなぜ 1.9.3 の時は、openssl がなくて大丈夫だったのだろう?)

brew で openssl を入れて、ruby-2.0.0 を入れ直す。

brew install openssl
rbenv uninstall 2.0.0-preview1
CONFIGURE_OPTS="--with-readline-dir=/usr/local/opt/readline --with-openssl-dir=/usr/local/opt/openssl" rbenv install 2.0.0-preview1
brew rehash
rbenv local 2.0.0-preview1
gem install bundler
bundle install
rspec spec

動いた

比較

2.0

$ rbenv local 2.0.0-preview1
$ rspec spec
Finished in 57.62 seconds

1.9

$ rbenv local 1.9.3-p327
$ rspec spec
Finished in 54.15 seconds

あれ・・・速くなってない・・・orz

まとめ

1. テストの書き方がうまく適さなかったのか速くなりませんでした orz

2. pry-debugger が動かなくなったので、解決方法を探す。ToDo. => (あとがき) こういう状況らしいです https://bugs.ruby-lang.org/issues/7214

どうしたこうなった・・・

zncを入れてみた

IRCで席をはずしている時に、自分のニックネームを自動的に xxxxx_away のように変えるのってどうやってるの?と聞いたところ、@ikasam_a 先生に znc を使ってるよ!と教えていただいたので自分でも試してみました。

zncとは: IRC Bouncer (IRC Proxy) です。どこかのサーバーにインストールしておくと、proxy が IRC サーバに接続し続けてくれます。手元の IRC クライアントから proxy に接続すると、自分が退席した間のログも取得することができます。複数のクライアントから接続した場合でも、IRCサーバには1人と見せることもできます。

znc のインストール

自分は tar ball からいれました。じゃないと simple_away がデフォで入っていなかったので。

$ wget http://znc.in/releases/znc-1.0.tar.gz
$ tar zxvf znc-1.0.tar.gz
$ cd znc-1.0
$ ./configure
$ make all
$ sudo make install

znc の初期設定

$ znc --makeconf

以下、入力例(ちょっと見づらい)。基本的にはデフォルト通りですが、管理画面があったら便利かなあと webadmin を入れたのと、本来の目的用の simple_away プラグインを入れる?という設問があったので、yes にしました。

[ ** ] Building new config
[ ** ] 
[ ** ] First let's start with some global settings...
[ ** ] 
[ ?? ] What port would you like ZNC to listen on? (1025 to 65535): 6667
[ ?? ] Would you like ZNC to listen using SSL? (yes/no) [no]: 
[ ?? ] Would you like ZNC to listen using ipv6? (yes/no) [yes]: 
[ ?? ] Listen Host (Blank for all ips): 
[ ok ] Verifying the listener... 
[ ** ] 
[ ** ] -- Global Modules --
[ ** ] 
[ ** ] +-----------+----------------------------------------------------------+
[ ** ] | Name      | Description                                              |
[ ** ] +-----------+----------------------------------------------------------+
[ ** ] | partyline | Internal channels and queries for users connected to znc |
[ ** ] | webadmin  | Web based administration module                          |
[ ** ] +-----------+----------------------------------------------------------+
[ ** ] And 10 other (uncommon) modules. You can enable those later.
[ ** ] 
[ ?? ] Load global module ? (yes/no) [no]: 
[ ?? ] Load global module ? (yes/no) [no]: yes                                                                                                                                                                                                               [45/1850]
[ ** ] 
[ ** ] Now we need to set up a user...
[ ** ] ZNC needs one user per IRC network.
[ ** ] 
[ ?? ] Username (AlphaNumeric): sonots
[ ?? ] Enter Password: 
[ ?? ] Confirm Password: 
[ ?? ] Would you like this user to be an admin? (yes/no) [yes]: 
[ ?? ] Nick [sonots]: 
[ ?? ] Alt Nick [sonots_]: 
[ ?? ] Ident [sonots]: 
[ ?? ] Real Name [Got ZNC?]: Naotoshi Seo
[ ?? ] Bind Host (optional): 
[ ?? ] Number of lines to buffer per channel [50]: 
[ ?? ] Would you like to keep buffers after replay? (yes/no) [no]: 
[ ?? ] Default channel modes [+stn]: 
[ ** ] 
[ ** ] -- User Modules --
[ ** ] 
[ ** ] +-------------+------------------------------------------------------------------------------------------------------------+
[ ** ] | Name        | Description                                                                                                |
[ ** ] +-------------+------------------------------------------------------------------------------------------------------------+
[ ** ] | admin       | Dynamic configuration of users/settings through IRC. Allows editing only yourself if you're not ZNC admin. |
[ ** ] | chansaver   | Keep config up-to-date when user joins/parts                                                               |
[ ** ] | keepnick    | Keep trying for your primary nick                                                                          |
[ ** ] | kickrejoin  | Autorejoin on kick                                                                                         |
[ ** ] | nickserv    | Auths you with NickServ                                                                                    |
[ ** ] | perform     | Keeps a list of commands to be executed when ZNC connects to IRC.                                          |
[ ** ] | simple_away | Auto away when last client disconnects                                                                     |
[ ** ] +-------------+------------------------------------------------------------------------------------------------------------+
[ ** ] And 35 other (uncommon) modules. You can enable those later.
[ ** ] 
[ ?? ] Load module ? (yes/no) [no]: 
[ ?? ] Load module ? (yes/no) [no]: 
[ ?? ] Load module ? (yes/no) [no]: 
[ ?? ] Load module ? (yes/no) [no]: 
[ ?? ] Load module ? (yes/no) [no]: 
[ ?? ] Load module ? (yes/no) [no]: 
[ ?? ] Load module ? (yes/no) [no]: yes
[ ** ] 
[ ** ] -- IRC Servers --
[ ** ] Only add servers from the same IRC network.
[ ** ] If a server from the list can't be reached, another server will be used.
[ ** ] 
[ ?? ] IRC server (host only): xxx.xxx.xxx.xxx
[ ?? ] [xxx.xxx.xxx.xxx] Port (1 to 65535) [6667]: 
[ ?? ] [xxx.xxx.xxx.xxx] Password (probably empty): 
[ ?? ] Does this server use SSL? (yes/no) [no]: 
[ ** ] 
[ ?? ] Would you like to add another server for this IRC network? (yes/no) [no]: 
[ ** ] 
[ ** ] -- Channels --
[ ** ] 
[ ?? ] Would you like to add a channel for ZNC to automatically join? (yes/no) [yes]: 
[ ?? ] Channel name: #test
[ ?? ] Would you like to add another channel? (yes/no) [no]: 
[ ** ] 
[ ?? ] Would you like to set up another user (e.g. for connecting to another network)? (yes/no) [no]: 
[ ok ] Writing config [/Users/seo.naotoshi/.znc/configs/znc.conf]... 
[ ** ] 
[ ** ] To connect to this ZNC you need to connect to it as your IRC server
[ ** ] using the port that you supplied.  You have to supply your login info
[ ** ] as the IRC server password like this: user:pass.
[ ** ] 
[ ** ] Try something like this in your IRC client...
[ ** ] /server  6667 sonots:
[ ** ] And this in your browser...
[ ** ] http://:6667/
[ ** ] 
[ ?? ] Launch ZNC now? (yes/no) [yes]: 
[ ok ] Opening Config [/Users/seo.naotoshi/.znc/configs/znc.conf]... 
[ ok ] Loading Global Module [webadmin]... [/usr/local/Cellar/znc/0.206/lib/znc/webadmin.so]
[ ok ] Binding to port [6667]... 
[ ** ] Loading user [sonots]
[ ok ] Adding Server [xxx.xxx.xxx.xxx 6667 ]... 
[ ok ] Loading Module [simple_away]... [/usr/local/Cellar/znc/0.206/lib/znc/simple_away.so]
[ ok ] Forking into the background... [pid: 25354]
[ ** ] ZNC 0.206 - http://znc.in

設定がおわると

~/.znc/configs/znc.conf

にファイルが作られているはず。

クライアントからの接続

znc を入れたマシンへ、指定したポート番号と指定したサーバパスワードで接続。

すると、znc でつないだチャンネル一覧が勝手に出るはず。

管理画面へのアクセス

セットアップ時に webadmin を入れたので、http://localhost:6667 で管理画面が表示されて、設定を変更できます。#Chrome だと変なポートが塞がれているかもしれないので Firefox で。

800px-Webadmin-settings-dark-clouds

自動 away 設定

管理画面 > webadmin > Your Settings > Edit `Networks` からモジュールを選択できます。ここで、

  • awaynick
  • simple_away

にチェックを入れて save します。これで時間が立ったり、ZNC から接続が切れた場合に自動的に away になります。

away 時のニックネームはデフォルトでは zz_元の名前 となるので変更したい場合、ドキュメント に書いてあるように、IRC クライアントから

/msg *awaynick set sonots_away

のようにして awaynick モジュールにメッセージを送って設定します。

複数クライアントから接続した場合でも Buffer Playback できるようにする。

znc を使うとデフォルトでチャンネルに再Joinしたときに不在中のチャットログが表示(Buffer Playback)されますが、第二クライアントから接続した場合、その Playback 済みの Buffer が消えてしまって、見る事ができません。第二クライアントから接続した場合でも、Buffer Playback できるようにするには、

管理画面 > List Users > Edit (an user) > Edit (a network) > Edit (a channel) から

  • Auto Clear Chan Buffer

のチェックをはずします。

  • Buffer Count

の値もデフォルトの 50 だと少ない気がするので、1000 などそれなりの数字に変えるとよさそうです。これを全チャネルに対して実施すればOKです。後記:1000だとでかすぎてバッファ読み込みおそ過ぎでした。100ぐらいですかね。

ちょっと面倒くさいので、.znc/configs/znc.conf で直接編集したい場合は、

    <Chan #ruby>
        AutoClearChanBuffer = false
        Buffer = 1000
    </Chan>

こんなかんじの設定になります。一括置換して znc を再起動すればよいでしょう。

znc の再起動方法

http://wiki.znc.in/Configuration にありますが、znc.conf を直接いじって再起動したい場合は

$ pkill -SIGUSR1 znc # to save current runtime configuration to znc.conf
$ pkill znc # to shutdown running ZNC instance
Edit znc.conf
$ znc

こんなかんじにコマンドを打ちます。

IRCログのファイル書き出し

Buffer Playback の機能もありますが、znc サーバのディスクにIRCログを書き出しておくこともできます。デフォルトだと Buffer はメモリ上のみに保存されるので簡単に消えてしまいます。

管理画面 > webadmin > Your Settings から

  • log

にチェックを入れて save します。これで、

~/.znc/users/{nickname}/moddata/log

ディレクトリにチャンネル毎のログファイルがディスク書き出しされるようになりあす。

とりあえずここまで!何かあったら追記します!

A Ruby and Fluentd committer working at DeNA. 記事本文および記事中のコード片は引用および特記あるものを除いてすべて修正BSDライセンスとします。 #ruby #fluentd #growthforecast #haikanko #yohoushi #specinfra #serverspec #focuslight
はてぶ人気エントリー