2011-09-13 36 views
0

我用下面的method_missing的實現給予一定的模型的適應性named_scope過濾實現動態named_scope:的Rails 2.3 - 使用混入

class Product < ActiveRecord::Base 
    def self.method_missing(method_id, *args) 

    # only respond to methods that begin with 'by_' 
    if method_id.to_s =~ /^(by\_){1}\w*/i 

     # extract column name from called method 
     column = method_id.to_s.split('by_').last 

     # if a valid column, create a dynamic named_scope 
     # for it. So basically, I can now run 
     # >>> Product.by_name('jellybeans') 
     # >>> Product.by_vendor('Cyberdine') 
     if self.respond_to?(column.to_sym) 
     self.send(:named_scope, method_id, lambda {|val| 
      if val.present? 
      # (this is simplified, I know about ActiveRecord::Base#find_by_..) 
      { :conditions => ["#{base.table_name}.#{column} = ?", val]} 
      else 
      {} 
      end 
     }) 
     else 
     super(method_id, args) 
     end 
    end 
    end 
end 

我知道這已經被的ActiveRecord :: Base的使用find_by_<X>提供的,但我我試圖超出我給出的例子的範圍,並提供一些定製的過濾器給我的應用程序。我希望將它提供給選定的模型,而不必在每個模型類中粘貼此代碼段。我想過使用一個模塊,然後將其混合到選擇的模型中 - 我對語法只是有點模糊。

據我已經得到了,因爲這時候的錯誤開始打樁(我在做這個吧?):

module GenericFilter 
    def self.extended(base) 

    base.send(:method_missing, method_id, *args, lambda { |method_id, args| 
    # ?.. 
    }) 

    end 
end 

然後,我希望能夠使用它,像這樣:

def Product < ActiveRecord::Base 
    include GenericFilter 
end 

def Vendor < ActiveRecord::Base 
    include GenericFilter 
end 

# etc.. 

任何幫助將是偉大的 - 謝謝。

回答

2

兩個實現這一

 
module GenericModule 
    def self.included(base) 
    base.extend ClassMethods 
    end 

    module ClassMethods 
    def methods_missing 
     #.... 
    end 
    end 
end 

class YourModel 
    include GenericModule 
    .. 
end 

 
    module GenericModule 
    def method_missing 
     #... 
    end 
    end 

    class MyModel 
    extend GenericModule 
    end 

的方法,我會建議使用的第一個,它似乎更清潔了我。而作爲一般建議,我會避免重寫method_missing :)。

希望這會有所幫助。

1

您需要在包含您的mixin的類的上下文中定義範圍。將範圍包裹在includes_class.class_eval中,並將self自己正確設置爲includes_class。

module Mixin 
    def self.included(klass) 
    klass.class_eval do 
     scope :scope_name, lambda {|*args| ... } 
    end 
    end 
end 

class MyModel 
    include Mixin 
end