2011-09-06 10 views
16

Voglio asciugare diversi modelli spostando gli ambiti condivisi in un modulo, qualcosa come:Ambiti condivisi tramite modulo?

module CommonScopes 
    extend ActiveSupport::Concern 

    module ClassMethods 
    scope :ordered_for_display, order("#{self.to_s.tableize}.rank asc") 
    end 
end 

Voglio anche di creare specifiche condivise che mettono alla prova il modulo. Sfortunatamente quando provo ad includere lo scope condiviso nel mio modello ottengo:

undefined method `order' for CommonScopes::ClassMethods:Module 

Qualche idea? Grazie!

risposta

13

È possibile utilizzare instance_eval

module CommonScopes 
    extend ActiveSupport::Concern 

    def self.included(klass) 
    klass.instance_eval do 
     scope :ordered_for_display, order("#{self.to_s.tableize}.rank asc") 
    end 
    end 
end 
+0

Non pensi che lambda debba essere preferito ora? – mdemolin

+0

@mdemolin Credo che chiamare 'scope' senza un lambda è deprecato in rails 4. – Gazler

+1

esattamente quello che stavo dicendo :) (ma penso che sia la sintassi preferita per ora, e non ancora deprecato) – mdemolin

2

Perché il vostro metodo di scope viene chiamato immediatamente quando il modulo viene analizzato da Ruby e non è accessibile dal modulo CommonScopes ..

Ma è possibile sostituire la chiamata portata da un metodo di classe:

module CommonScopes 
    extend ActiveSupport::Concern 

    module ClassMethods 
    def ordered_for_display 
     order("#{self.to_s.tableize}.rank asc") 
    end 
    end 
end 
37

Come in rotaie 4 scope syntax si può semplicemente utilizzare un lambda per ritardare l'esecuzione del codice (funziona anche su rails 3):

module CommonScopes 
    extend ActiveSupport::Concern 

    included do 
    scope :ordered_for_display, -> { order("#{self.to_s.tableize}.rank asc") } 
    end 
end 
+0

È il modo migliore. –