• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
 

named_scope more detail

on

  • 7,583 views

detail explanation of named_scope, Rails 2.1's killer future. lang:ja

detail explanation of named_scope, Rails 2.1's killer future. lang:ja

Statistics

Views

Total Views
7,583
Views on SlideShare
5,222
Embed Views
2,361

Actions

Likes
3
Downloads
42
Comments
0

22 Embeds 2,361

http://d.hatena.ne.jp 2072
http://rubyrailsandwindows.blogspot.com 158
http://okyuu.com 47
http://coderwall.com 34
http://rubyrailsandwindows.blogspot.in 10
http://webcache.googleusercontent.com 6
http://www.slideshare.net 5
http://rubyrailsandwindows.blogspot.com.au 4
http://74.125.153.132 4
http://rubyrailsandwindows.blogspot.de 3
http://triple-c.sakura.ne.jp 3
http://rubyrailsandwindows.blogspot.com.br 3
http://rubyrailsandwindows.blogspot.co.uk 2
http://rubyrailsandwindows.blogspot.ca 2
http://rubyrailsandwindows.blogspot.co.il 1
http://rubyrailsandwindows.blogspot.com.ar 1
http://rubyrailsandwindows.blogspot.pt 1
http://209.85.173.132 1
http://rubyrailsandwindows.blogspot.co.nz 1
http://72.14.235.104 1
http://72.14.235.132 1
http://rubyrailsandwindows.blogspot.no 1
More...

Accessibility

Categories

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 named_scope more detail Presentation Transcript

    • named_scopeについてくわしく(株)永和システムマネジメント ¦¦ Rails勉強会@東京 諸橋 恭介 (もろはし きょうすけ) k-morohashi@esm.co.jp (work) moronatural@gmail.com (private)
    • What’s this?• with_scopeで使っていた「スコープを掛けた」検索を、ク ラスメソッドとして定義できるようになる仕組みです。• ちょうどRails 2.0からwith_scope()がprotected(笑)に なって困っていた人にとっての福音となりそうです。• 定義したスコープは、都度実行されるわけでなく、 AssociationProxy的にレイジーに賢く実行されます。• Rails 2.1の目玉機能でRubyKaigiで松田さんが話しましたhttp://www.slideshare.net/a_matsuda/ new-wave-of-database-programming-with-ruby-19-on-rails-21/
    • with_scopeってなんだっけ Recipe 077 (p.220) 検索条件をスコープ毎に まとめて定義するhttp://www.amazon.co.jp/dp/4797336625
    • なにができるの?• named_scope()で定義した「集合」を掛け合わせて 操作できます。• RDBMSをOOPの世界に引っ張ってきたORMは偉大 ではありますが、その過程で集合演算という色合いは 薄れ、単なるSQL/RDBMSはオブジェクトの永続化 方法のように扱われてしまいがちです • ORMを使うとSQL知らなくても。。。という言質が端的に示してい ますね• 集合演算を再び我が手に!! ということで named_scope()の説明です。
    • Examples
    • active usersclass User < ActiveRecord::Base named_scope :active, :condition=>["deleted = ?", false]enddescribe “activeなユーザ” do it “は全員削除されて*いない*こと” do User.active.should be_all{|u| not u.deleted } endend
    • active users (with guideline)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
    • hot n users use scope with argsclass User < ActiveRecord::Base named_scope :active, :condition=>["deleted = ?", false] named_scope :hot, Proc.new{|arg| {:order =>"#{table_name}.popularity DESC", :limit => arg} }end
    • hot n users use scope with argsdescribe “人気トップ3のユーザ” do before do @users = User.hot(3) end it "のうちトップはdahliaであること" do @users.first.should == users(:dahlia) endend
    • hot active users crossover 2 scopesdescribe "BAN! dahlia" do before(:each) do users(:dahlia).update_attribute(:deleted, true) end it "アクティブユーザで最も人気なのはcharlesであること" do User.hot(3).active.first.should == users(:charles) end it "クエリ発行(select_all)は一回だけ呼ばれること" do User.connection.should_receive(:select_all).once.and_return([]) User.hot(3).active.find(:all) endend
    • update using scopeclass User < ActiveRecord::Base named_scope :active, :conditions=>["#{table_name}.deleted = ?", false] do def ban self.update_all(:deleted => true) end end named_scope :hot, Proc.new{|arg| {:order =>"#{table_name}.popularity DESC", :limit => arg} }end
    • update using scopedescribe “User.active.ban” do it "activeユーザ全員がBANされること" do User.active.ban User.should have(0).active end it "UPDATE文は一度だけ発行されること" do User.connection.should_receive(:update).once User.active.ban endend
    • Implementations
    • ActiveRecord::Baseへ 追加されるメソッド• ActiveRecord::Base.scopes() • 定義されているscopeを返す。  inheritable_attributeで保持されてる。• ActiveRecord::Base.named_scope() • 第一引数にscope名,第二引数にHash形式でfind パラメータを渡す • 第二引数にfindパラメータを返すProcを渡すと実行 時に評価される。
    • named_scope宣言をkwsk• named_scope宣言でscopeを定義する • 内部では実行時にScopeオブジェクトを作るProc を作る。 • それを呼び出すクラスメソッドも追加される。 • ブロック付きで呼び出すと無名モジュールを作って Scopeオブジェクトに追加する • このブロックは第二引数のProcオブジェクトとは 別物。このへんが1.9だとキレイだという所以。
    • AR::Base.named_scopedef named_scope(name, options = {}, &block) scopes[name] = lambda do |parent_scope, *args| Scope.new(parent_scope, case options when Hash options when Proc options.call(*args) end, &block) end (class << self; self end).instance_eval do define_method name do |*args| scopes[name].call(self, *args) end endend
    • Scopeオブジェクト• ArrayのようでArrayじゃないアレ • みんな大好きAssociationProxyと同じ感じ • Arrayぽい動きはload_found()でロードしたモ デルオブジェクトのArrayに委譲 • みんな大好きmethod_missingで頑張ってる
    • Scope.new(parent,options,&block)• 第一引数は親スコープ • Scopeインスタンス or AR::Base • 最初は必ずAR::Base• 第二引数がfindパラメータ• ブロックを渡すとScopeオブジェクトのメソッ ドを追加できる ‣ ex => User.active.ban
    • Scope#method_missing• method_missingで「親スコープ」を使う• 呼ばれたメソッドに対応する名前付きscopeがあれば 子Scopeを作るProcをcallする • 子Procには親スコープとしてselfを渡す• なければ自身のfindパラメータを使って親スコープの当該 メソッドを呼び出す
    • 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
    • Conclusion
    • call sequence ofUser.active.hot(3).each do |u| do_somethingend
    • call sequence - generate Scope instance -User#active#=> <#Scope:active, @proxy_scope=>User><#Scope:active>#hot(3)---> <#Scope:active>#method_missing(:hot)# scope[:hot] != nilであるため#=> <#Scope:hot, @proxy_scope=> <# Scope:active>>
    • call sequence - 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 }
    • 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] )
    • ご清聴ありがとうございました