Rubyを使い始めた (2) - Rails3のArelの例

はじめに

サンプルとして、下記のようなModelとデータベースを作成してある。

$ rails g model book name:string
$ rails g model user name:string lang:string age:integer book:references
  • books
id name
1 レガシーコード改善ガイド
2 情熱プログラマ
3 メタプログラミングRuby
  • users
id name lang age book_id
1 sinsoku python 24 1
2 _ryog java 24 2
3 NowTom ruby 28 3
4 tosikawa python 30 2

* サンプルのデータは実在の人物とは関係ありません

find とwhere の違い

日本語で説明するよりも、コードを見た方が早いので、例

Rails2 のfind

User.find(:first, :conditions => ["lang = ? and age = ?", 'python', 24])

Rails3 のwhere

User.where(:lang => 'python').where(:age => 24).first

上記の例のように、whereを使用するとname_scope のような書き方が出来ます。

使い方の例

  • where句
User.where(:lang => 'python').all
# => [#<User id:1, name: "sinsoku", lang: "python", age: 24, book_id: 1, create_at: ..., updated_at: ...>,
#     #<User id:4, name: "tosikawa", lang: "python", age: 30, book_id: 2, create_at: ..., updated_at: ...>]

User.where(:name => 'sinsoku').first
# => #<User id:1, name: "sinsoku", lang: "python", age: 24, book_id: 1, create_at: ..., updated_at: ...>

ちなみに、findのような引数も使えます。

User.where(['name = ? and lang = ?', 'NowTom', 'ruby']).first
# => #<User id:3, name: "NowTom", lang: "ruby", age: 28, book_id: 3, create_at: ..., updated_at: ...>
  • order句
users = User.arel_table
User.where(:lang => 'python')
    .order(users[:age].asc).all
# => [#<User id:1, name: "sinsoku", lang: "python", age: 24, book_id: 1, create_at: ..., updated_at: ...>,
#     #<User id:4, name: "tosikawa", lang: "python", age: 30, book_id: 2, create_at: ..., updated_at: ...>]

User.where(:lang => 'python')
    .order(users[:age].desc).all
# => [#<User id:4, name: "tosikawa", lang: "python", age: 30, book_id: 2, create_at: ..., updated_at: ...>,
#     #<User id:1, name: "sinsoku", lang: "python", age: 24, book_id: 1, create_at: ..., updated_at: ...>]
  • include句
books = Book.arel_table
User.where(:age => 24)
    .where(books[:name].eq('情熱プログラマー'))
    .includes(:book).first
# => #<User id:2, name: "_ryog", lang: "java", age: 24, book_id: 2, create_at: ..., updated_at: ...>
  • and条件
users = User.arel_table
users.where(users[:age].lt(25).and(users[:lang].eq('java'))).first
# => #<User id:2, name: "_ryog", lang: "java", age: 24, book_id: 2, create_at: ..., updated_at: ...>

# 長いときはこっちの方が見易い
users.where(['age < ? and lang = ?', 25, 'java']).first
# => #<User id:2, name: "_ryog", lang: "java", age: 24, book_id: 2, create_at: ..., updated_at: ...>
  • or条件
users = User.arel_table
User.where(users[:name].eq('sinsoku').or(users[:lang].eq('ruby'))).all
# => [#<User id:1, name: "sinsoku", lang: "python", age: 24, book_id: 1, create_at: ..., updated_at: ...>,
#     #<User id:3, name: "NowTom", lang: "ruby", age: 28, book_id: 3, create_at: ..., updated_at: ...>]

# こういう書き方も出来ます
User.where(users[:lang].eq_any(['java', 'ruby'])).all
# => [#<User id:2, name: "_ryog", lang: "java", age: 24, book_id: 2, create_at: ..., updated_at: ...>,
#     #<User id:3, name: "NowTom", lang: "ruby", age: 28, book_id: 3, create_at: ..., updated_at: ...>]
  • not 条件
users = User.arel_table
User.where(users[:name].not_eq('sinsoku')).all
# => [#<User id:2, name: "_ryog", lang: "java", age: 24, book_id: 2, create_at: ..., updated_at: ...>,
#     #<User id:3, name: "NowTom", lang: "ruby", age: 28, book_id: 3, create_at: ..., updated_at: ...>,
#     #<User id:4, name: "tosikawa", lang: "python", age: 30, book_id: 2, create_at: ..., updated_at: ...>]
  • 遅延評価してる例
pythonista = User.where(:lang => 'python')
pythonista.all
# => [#<User id:1, name: "sinsoku", lang: "python", age: 24, book_id: 1, create_at: ..., updated_at: ...>,
#     #<User id:4, name: "tosikawa", lang: "python", age: 30, book_id: 2, create_at: ..., updated_at: ...>]

books = Book.arel_table
pythonista_with_legacy = pythonista.where(books[:name].eq('レガシーコード改善ガイド')).includes(:book)
pythonista_with_leagacy.all
# => [#<User id:1, name: "sinsoku", lang: "python", age: 24, book_id: 1, create_at: ..., updated_at: ...>]

おまけ

Arelのソースを読める方や英語のドキュメントを探し出せる方*1には関係のない話ですが、
上記の方法以外で、簡単にArelのメソッドを調べる方法を紹介しておきます。

$ rails c
$ ruby-1.9.2-p136 :001 > Arel::Table.new.[Tab]

Tab補完で、Arelのメソッド一覧が出てきます。
SQLっぽい単語を入れて、Tab補完で出てきたら、たぶんSQLと同じ意味で使えると思います。

*1:探したけど、私は見つけられなかった・・・