2011-09-13 10 views
0

を使用して動的named_scopeを実装する:私はこれは既にfind_by_<X>を使用してのActiveRecord :: Baseが提供される知っているレール2.3 - 私は特定のモデルに適合named_scopeフィルタリングを与えるために、次のmethod_missing実装を使用ミックスイン

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 

を、私私が与えた例を少し超えて、私のアプリケーションにいくつかのカスタムフィルタリングを提供しようとしています。私はそれをすべてのモデルクラスにこのスニペットを貼り付けることなく、選択されたモデルで利用できるようにしたいと思います。私はモジュールを使用して、それを選択したモデルで混合することを考えました - 私は構文について少し曖昧です。

エラーが積み上げ始めたとき、私は(私はこの権利をやっている?)限り、このように得ている:

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.. 

ご協力いただきありがとうございます。ありがとうございます。私は最初のものを使用することをお勧めしこの

 
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 

を達成するための

答えて

2

つの方法は、その私にはきれいそうです。そして一般的なアドバイスとして、私はmethod_missingをオーバーライドするのを避けるだろう:)。

これが役に立ちます。

1

ミックスインを含むクラスのコンテキスト内でスコープを定義する必要があります。 include_class.class_evalにスコープをラップすると、selfは正しくinclude_classに設定されます。

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

class MyModel 
    include Mixin 
end 
関連する問題