Skip to main content

ログ取得ツール (移転先予定地)

ActiveRecordとSequel

RubyのORMはいくつかあるが、Railsで使われているActiveRecordが最もメジャーで、その次くらいにSequelがあると認識している。

最近ふとしたことで両方を使ってみた感想。どちらも、テーブル名を複数形(sつき)にしなきゃいけなかったり、いろいろ面倒だった。勝手に変化させないで欲しいんだよねー。おれ、プログラム上で語尾を変化させるのは好きじゃないのよね。-erと-orの違いとか、sつけるのつけないの、esやiesになるの、受け身だからedだとか、haveかhasかhadとかhavenとか、isかareか、theをつけるかつけないかとか、datumかdataかなんて、考えたくないじゃん。ただのシンボルなんだから。

そういう細かいアレがあるにせよ、どちらも割と使えたんだけど、ActiveRecordはDB側のconstraintを指定できず、例えばカジュアルにuniqueをつけたいと思ってもできない。Ruby側でvalidationを書くかインデックスにuniqueをつけるかしなければならなかったりして、今のところSequelのほうが使用感は良い。ActiveRecordがモデルの記述を重点しているのに対し、Sequelはモデルがなくてもかなりイイトコまで働ける感じ。

例えばJoinの書き方に関してはSequelのほうが直感的で分かりやすい。現代においてSQLを使うというのはすなわちJoinを使うということであるようなのだが、Sequelはモデルに何も書かなくてもキーをjoinの引数に指定するだけでjoinできる。ActiveRecordはモデルにリレーション(belongs_toだの何だの)をつけないとjoinできない。そもそもjoinじゃなくてjoinsなんだよな…三人称単数現在…そこでそうするか。SQLではJOINSなんて書けないよ。んなこと言うならおめーはActiveRecordsじゃねえのかッコラー!!

ただSequelのjoinは同じカラム名のものがあるときに、間違った(と私が思う)結果が返ってきてしまうことに気づいた。意味的に考えてバグっている気がする。

つまり、こうだ。

[pyg language=“ruby”] #! /usr/bin/ruby

require ‘sequel’ require ‘pp’

DB=Sequel.sqlite

DB.create_table :tbl1s do primary_key :id String :value end

DB.create_table :tbl2s do primary_key :id String :value2 Integer :tbl1_id end

class Tbl1 < Sequel::Model ; end class Tbl2 < Sequel::Model ; end

if $0==__FILE__ Tbl1.insert(:value=>“tbl1data1”) # tbl1s.id=>1 Tbl1.insert(:value=>“tbl1data2”) # tbl1s.id=>2 Tbl2.insert(:value2=>“tbl2data1”, :tbl1_id=>2) # tbl2s.id=>1 Tbl2.insert(:value2=>“tbl2data2”, :tbl1_id=>1) # tbl2s.id=>2

SELECT * FROM tbl1s INNER JOIN tbl2s ON (tbl2s.tbl1_id = tbl1s.id)

t=Tbl1.join(Tbl2, :tbl1_id=>:id).first pp t # Tbl1{:id=>1, :value=>“tbl1data2”, :value2=>“tbl2data1”, :tbl1_id=>2} end [/pyg]

Tbl1.join(Tbl2)だと、Tbl1のオブジェクトが返るが、その:idはなんとTbl2のものなので、戻ってきたTbl1オブジェクトをそのまま扱っていると大変な事故が起きる。例えばこれで中身を見てdeleteしたら、思ったのと異なるものが削除されてしまう(No!)。これを避けるには、こんなふうに↓書かなければならなかった。

Tbl1.join(Tbl2, :tbl1_id=>:id).select(*Tbl1.columns.map{|m| Sequel.qualify(:tbl1s, m) })

これって、モデルで関連をちゃんと書けばいいという話なんだろうか? 戻るのはTbl2じゃなくてTbl1のオブジェクトなんだから、selectやモデル定義で小細工しなくてもTbl1側のカラム名が優先されるのが当然に思えるんだけど。