named_scope more detail - WebCareer
Upcoming SlideShare
Loading in...5
×
 

named_scope more detail - WebCareer

on

  • 2,624 views

talked about AR.named_scope in Rails Summer Festival 2008 by WebCareer

talked about AR.named_scope in Rails Summer Festival 2008 by WebCareer

Statistics

Views

Total Views
2,624
Views on SlideShare
2,591
Embed Views
33

Actions

Likes
3
Downloads
9
Comments
0

3 Embeds 33

http://coderwall.com 31
http://lifeast.net 1
http://www.slideee.com 1

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

named_scope more detail - WebCareer named_scope more detail - WebCareer Presentation Transcript

  • named_scopeについてくわしく(株)永和システムマネジメント ¦¦ Rails勉強会@東京 諸橋 恭介 (もろはし きょうすけ) k-morohashi@esm.co.jp (work) moronatural@gmail.com (private)
  • まとめ• named_scopeを使うと、複雑な検索条 件をシンプルかつ柔軟に記述できる• 技術的にずいぶんおもしろい • とてもかっこいいmethod_missingの よい使い方
  • これはなに?• かつてRailsには with_scope という APIがありました• with_scopeを使うと、検索条件を指定 する「スコープ」を定義できます • そのスコープ内での検索には、自動的 にスコープの条件が付加されます
  • with_scopeの例User.find(:all)# SELECT * FROM usersUser.find(:all, :conditions=>[“deleted=?”,false])# SELECT * FROM users WHERE deleted = 0User.with_scope( :find=>{:conditions=>[“deleted=?”,false]}) do User.find(:all)end# SELECT * FROM users WHERE deleted = 0
  • with_scopeについて Recipe 077 (p.220) 検索条件をスコープ毎に まとめて定義するhttp://www.amazon.co.jp/dp/4797336625
  • What’s named_scope?•with_scopeで使っていた「検索スコー プ」に名前が付けられます。•Rails 2.1の目玉機能です • RubyKaigi 2008でも松田さんが話しましたhttp://www.slideshare.net/a_matsuda/ new-wave-of-database-programming-with-ruby-19-on-rails-21/
  • なにがすごいの?•名前を付けたスコープ同士を掛け合わせられます。• DBアクセスは、 必要となった時点で賢く(多くは1回だ け)実行されます。•「微妙に条件の異なる検索」の多くをスコープの掛け合わせで表現できます
  • ORMとRDBMS• RDBMSをOOPの世界に引っ張ってきた ORMはすごい!!• しかしORMを使うと、RDBMSは単なる オブジェクトの永続化ストレージのように 扱いがちです。• named_scopeを使うと、RDBの集合演 算が持つ力の一部をOOPの世界でも使える 感じになります。
  • named_scopeの 例
  • 有効なユーザ usersactive users
  • 有効なユーザclass User < ActiveRecord::Base named_scope(:active, {:condition=>["deleted = ?", false]})enddescribe “activeなユーザ” do it “は全員削除されて*いない*こと” do User.active.should be_all{|u| not u.deleted } endend
  • 人気のあるユーザ実行時にscopeの一部を指定 users hot users
  • 人気のあるユーザ 実行時にscopeの一部を指定class User < ActiveRecord::Base named_scope :active, :condition=>["deleted = ?", false] named_scope :hot, Proc.new{|arg| {:conditions=>[“popularity > ?”, arg], :order =>"popularity DESC"} }end
  • 人気のあるユーザ 実行時にscopeの一部を指定describe “人気度80以上のユーザ” do before do @users = User.hot(80) end it "のうちトップはdahliaであること" do @users.first.should == users(:dahlia) endend
  • 人気かつ有効なユーザ crossover 2 scopes usersactive users users hot
  • 人気かつ有効なユーザ crossover 2 scopesdescribe "BAN! dahlia" do before(:each) do # dahliaの削除フラグを立てる つまり active usersの集合から外す users(:dahlia).update_attribute(:deleted, true) end it "アクティブユーザで最も人気なのはcharlesであること" do User.active.hot(80).first.should == users(:charles) end it "クエリ発行(select_all)は一回だけ呼ばれること" do User.connection.should_receive(:select_all).once.and_return([]) User.hot(80).active.find(:all) endend
  • 他にも好きな条件を 追加できる usersactive users n users hot Other..
  • named_scope 実行時の動きUser.active.hot(80).each do |u| do_somethingend
  • User.active.hot(80) - generate Scope instance -User#active#=> <#Scope:active, @proxy_scope=>User><#Scope:active>#hot(3)---> <#Scope:active>#method_missing(:hot)# scopes.include?(:hot)であるため#=> <#Scope:hot, @proxy_scope=> <# Scope:active>>
  • Scope#method_missing•User#activeはUserクラスを親スコープとしたScopeを作る•Scope#method_missingは呼ばれたメソッドに対応する子Scopeを作る• 子Procには親スコープとしてselfを渡す
  • Scope#method_missingdef method_missing(method, *args, &block) if scopes.include?(method) scopes[method].call(self, *args) else with_scope :find => proxy_options do proxy_scope.send(method, *args, &block) end endend
  • User.active.hot(80) - execute and respond to method -<#Scope:hot, @proxy_scope=> <#Scope:active>>#each---> <#Scope:hot>#proxy_found---> <#Scope:hot>#find(:all)---> <#Scope:hot>method_missing(:find)---> <#Scope:hot>#with_scope{ <#Scope:active>#find }---> <#Scope:active>#method_missing(:find)---> <#Scope:active>#with_scope{ User.find(:all) }# => [<#User:..>, .... ][<#User:..>, ...].each{ do_something }
  • Scope#method_missing•呼ばれたメソッドに対応するScopeが定義されていない場合• 自身のfindパラメータでwith_scopeし、親ス コープの当該メソッドを呼び出す
  • Scope#method_missingdef method_missing(method, *args, &block) if scopes.include?(method) scopes[method].call(self, *args) else with_scope :find => proxy_options do proxy_scope.send(method, *args, &block) end endend
  • with_scopeで 書き直したイメージUser.with_scope( :find=>{:conditions=>[”popularity>?”, 80], :order=>”popularity” }) do User.with_scope( :find=>{:conditons=>[“deleted=?”, false]}) do User.find(:all).each{ ... } endend Rails2.xではこのままでは動きません
  • まとめ• named_scopeを使うと、複雑な検索条 件をシンプルかつ柔軟に記述できる• 技術的にずいぶんおもしろい • とてもかっこいいmethod_missingの よい使い方
  • you.any?{|u| u.question?}
  • FAQ: スコープはどんなふ うに結合されるの?• 後ろから順にwith_scopeを使います。 • WHERE句相当(:conditionsパラメータ)はANDで 結合されます。 • ORDERやLIMITは先に指定したscopeで指定して いるものがそのまま使われるっぽいです。 • この辺りのロジックは activerecord-2.1.0/lib/ active_record/base.rb : 1807 あたりを参照
  • FAQ: Ruby 1.9だとよりカッコ良いという噂があるが? • Procオブジェクト生成に->記法が使えます 旧 named_scope :hot, Proc.new{|arg| {:order =>"popularity DESC", これが :limit => arg} } こうなる named_scope :hot, ->{ {:order =>"popularity DESC", 新 } :limit => arg}
  • FAQ: テストがよりカッコ良く 書けるという噂があるが? • mockするのが楽にキレイになりそうな感じ。 旧 User.should_receive(:find). with(:all,:condition=>[...]). これが and_return( [alice] ) こうなる User.shold_receive(:active) 新 and_return( [alice] )
  • with_scopeについて Recipe 077 (p.220) 検索条件をスコープ毎に まとめて定義するhttp://www.amazon.co.jp/dp/4797336625
  • ご清聴 ありがとうございました