akishin999の日記

調べた事などを書いて行きます。

Rails3 で acts_as_tritonn

Rails2 + Tritonn の時には結構お世話になっていた acts_as_tritonn を Rails3 で使ってみました。

インストール

$ rails new tritonn_example -d mysql
$ cd tritonn_example
$ rails plugin install git://github.com/ryu00026/acts_as_tritonn.git

使ってみる

config/database.yml に Tritonn への接続設定を記述し、rails console で接続。
find_fulltext を呼び出したところで、以下のようなエラーが発生しました。

$ rails c
Loading development environment (Rails 3.0.9)
ruby-1.9.2-p180 :001 > Entry.find_fulltext(:title => 'Ruby')
NameError: uninitialized constant ActiveSupport::Multibyte::Handlers
        from /home/akishin/src/ruby/tritonn_example/vendor/plugins/acts_as_tritonn/lib/tritonn/searchable.rb:64:in `block in fulltext'
        from /home/akishin/src/ruby/tritonn_example/vendor/plugins/acts_as_tritonn/lib/tritonn/searchable.rb:60:in `each_pair'
        from /home/akishin/src/ruby/tritonn_example/vendor/plugins/acts_as_tritonn/lib/tritonn/searchable.rb:60:in `fulltext'
        from /home/akishin/src/ruby/tritonn_example/vendor/plugins/acts_as_tritonn/lib/tritonn/searchable.rb:50:in `find_fulltext'
        from (irb):1
        from /home/akishin/src/ruby/tritonn_example/vendor/bundle/ruby/1.9.1/gems/railties-3.0.9/lib/rails/commands/console.rb:44:in `start'
        from /home/akishin/src/ruby/tritonn_example/vendor/bundle/ruby/1.9.1/gems/railties-3.0.9/lib/rails/commands/console.rb:8:in `start'
        from /home/akishin/src/ruby/tritonn_example/vendor/bundle/ruby/1.9.1/gems/railties-3.0.9/lib/rails/commands.rb:23:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'

以前 2.2 系で使おうとした時に見たことあるエラーです。
その時は以下のサイトにお世話になったのですが、今見るとどうやら消えてしまっているようですね。

whatever I wanna talk - MySQL tritonn (senna) で全文検索 on Rails 2.2.2
http://www.silver-island.com/jp/blog/2009/02/mysql_triton_senna_on_rails_22_1.html

2.2 の時は、こちらサイトで教えて頂いた、searchable.rb に対する以下の修正を行うことでこのエラーは回避できていました。

$ vim vendor/plugins/acts_as_tritonn/lib/tritonn/searchable.rb

64行目の辺りを以下のように修正。

# ANDか通常の検索
ary = string.split(/[#{ActiveSupport::Multibyte::Handlers::UTF8Handler.codepoints_to_pattern(ActiveSupport::Multibyte::Handlers::UTF8Handler::UNICODE_WHITESPACE)}]+/)

# ANDか通常の検索
if ActiveSupport::VERSION::MAJOR >=2 and ActiveSupport::VERSION::MINOR >=2 
  ary = string.split(/[#{ActiveSupport::Multibyte::Chars.codepoints_to_pattern(ActiveSupport::Multibyte::Chars::UNICODE_WHITESPACE)}]+/)
else
  ary = string.split(/[#{ActiveSupport::Multibyte::Handlers::UTF8Handler.codepoints_to_pattern(ActiveSupport::Multibyte::Handlers::UTF8Handler::UNICODE_WHITESPACE)}]+/)
end

※ 移転先が見つからななかったため、こちら転載させて頂きました

修正内容

エラーの内容からすると今回も同様の修正になりそうです。
念のため、Rails3 で codepoints_to_pattern メソッドがどうなったか調べてみます。

codepoints_to_pattern (ActiveSupport::Multibyte::Chars) - APIdock
http://apidock.com/rails/ActiveSupport/Multibyte/Chars/codepoints_to_pattern/class

ここを読むと、ActiveSupport::Multibyte::Chars.codepoints_to_pattern は 2.3.8 までで、現在は同等のメソッドとして ActiveSupport::Multibyte::Unicode#codepoints_to_pattern を使え、ということのようですね。
また、引数で指定している ActiveSupport::Multibyte::Chars::UNICODE_WHITESPACE に関しても、ActiveSupport::Multibyte::Unicode::WHITESPACE の方を使うようになったみたいです。

これらを踏まえ、searchable.rb を以下のように修正してみました。

# ANDか通常の検索
if ActiveSupport::VERSION::MAJOR >=3
  ary = string.split(/[#{ActiveSupport::Multibyte::Unicode.codepoints_to_pattern(ActiveSupport::Multibyte::Unicode::WHITESPACE)}]+/)
elsif ActiveSupport::VERSION::MAJOR >=2 and ActiveSupport::VERSION::MINOR >=2
  ary = string.split(/[#{ActiveSupport::Multibyte::Chars.codepoints_to_pattern(ActiveSupport::Multibyte::Chars::UNICODE_WHITESPACE)}]+/)
else
  ary = string.split(/[#{ActiveSupport::Multibyte::Handlers::UTF8Handler.codepoints_to_pattern(ActiveSupport::Multibyte::Handlers::UTF8Handler::UNICODE_WHITESPACE)}]+/)
end

rails console で確認すると今度はエラーは発生せず、検索結果も取得できています。
log/development.log に出力されるログを見ても以下のように、以前と同様のクエリが出力されていました。

SELECT `entries`.* FROM `entries` WHERE (MATCH(title) AGAINST (" +Ruby" IN BOOLEAN MODE))

これで修正は OK と言えそうです。
Tritonn はお手軽に全文検索システムを作るのに便利なので、これで Rails3 からも気軽に使う事ができるようになったのは嬉しいです。