Posts Tagged ‘Arel’

    はてなブックマーク - Rails3 Arel ActiveRecord::Relation考察
    このエントリーをはてなブックマークに追加

    夏が過ぎ風あざみ。

    謎の首痛と腰痛、そして風邪に見舞われた8月でしたが、
    人にうつせば治るというもので、すっかりよくなった山本です。

    今日はRails3のコネタを。

    Arel

    Rails3では、O/RマッパーであるActiveRecordが進化を遂げ、「Arel」というライブラリを使用するようになりました。
    「Arel」については様々なサイトで解説が載ってますが、
    Rails2のfind系メソッドは、呼び出しの際にDBに対してSQLを発行していたのが、
    Rails3では、インスタンスは一旦、 ActiveRecordのサブクラスである、 Relationのオブジェクトとして格納されます。
    全部が全部ではないですが。

    例えば、Userモデルがあるとして、

    user = User.find(1)

    と、findを使ってデータを取得して、userの中身を見ると

    user.class
    => User(id: integer, email: string, .....created_at: datetime, updated_at: datetime)

    と、Userモデルのインスタンスになっていますが、

    user = User.where(:id => 1)

    と、whereを使うと、

    user.class
    => ActiveRecord::Relation

    となります。

    そしてこの時、SQLの処理は行われません。
    あくまで関係の定義が詰まっているだけ。

    この利点は、不要不急なSQL処理が走らないことですね。
    また、これこそが、whereを数珠つなぎにして条件を加える、メソッドチェーンの書き方ができるわけです。

    user = User.where(:id => 1)
    user = user.where("number  > 1")
    user = user.where("type  > 2")

    と書いて、3回もSQLが走ったら大変ですし。

    じゃあいつクエリが発行されるのかというと、
    実際に値を表示するときです。

    例えば、
    puts user

    user.all
    などと書いたときですね。

    本当に値が必要になったときに処理をしてくれるので、リソースの節約につながるのかなと。

    逆効果も

    ただ、使い方を誤ると逆に無駄にクエリを発行することにもなります。

    ある条件のデータの最大と最小を取り出したい、といった時、
    僕はこう書いてました。

    user = User.order("id ASC")
    user_min = user.first
    user_max = user.last

    rails2時代の感覚だと、1行目でレコードのデータが user に格納され、
    2行目と3行目では、ただの配列の操作を行ってデータを格納する処理ですが、
    実際には1行目では user にデータは格納されず、
    2行目と3行目でクエリが発行されてデータが格納されます。
    つまり、1回余分です。

    これじゃあ無駄なので、1行目を

    user = User.order("id ASC").all

    としました。

    こうすれば、1行目で user にデータが格納され、クエリ発行は1回です。

    時代はもうRails3.1

    まだ、Arelに馴染んでなかったといってしまえばそれまでですが、
    rails2の感覚でいると、いろいろ壁があるなーと実感しました。
    今やもう3.1ですし、次はcoffeescriptをやらないといけないかなと思ってます。
    上記は、あくまで自分の解ですが、他の解とか、そもそも論が何かあればツッコミのほどよろしくお願いします。