1

我创建了一个包含在类中的模块。在模块中,我试图定义一个方法,它是没有过滤器的类名的小写版本。所以 ShowFilter 会有一个名为 show 的方法,它返回类 Show。我得到“NoMethodError:ShowFilter:Class 的未定义方法‘show’”

module Filters

  module Base

    module ClassMethods

      @@filters = {}

      def filter name, &block
        @@filters[name] = block
      end

      def run query = {}
        query.each do |name, value|
          @@filters[name.to_sym].call(value) unless @@filters[name.to_sym].nil?
        end
        self
      end

      def self.extended(base)
        name = base.class.name.gsub(/filter/i, '')
        define_method(name.downcase.to_sym) { Kernel.const_get name }
      end


    end

    def self.included base
      base.extend ClassMethods
    end

  end

end


class ShowFilter
    include Filters::Base

    filter :name do |name|
        self.show.where(:name => name)
    end

end

编辑:使用示例

class ShowController < ApplicationController
  def index
    ShowFilter.run params[:query]
  end
end
4

1 回答 1

3

当您定义Filters::Base::ClassMethods时,它会在该上下文中评估 self ,因此您最终定义的方法是ClassMethods.classmethods(因为 gsub 不会做任何事情)。

就像您在 Base 中使用的包含挂钩一样,您希望在 ClassMethods 中使用扩展:

module Filters
  module Base
    module ClassMethods

      @@filters = {}

      def filter name, &block
        @@filters[name] = block 
      end 

      def run query = {} 
        query.each do |name, value| 
          @@filters[name.to_sym].call(value) unless @@filters[name.to_sym].nil? 
        end 
        Object.const_get(self.to_s.gsub('Filter', '')) 
      end 

      def self.extended(base) 
        define_method(base.to_s.downcase.gsub('filter', '').to_sym) do 
          Object.const_get(self.to_s.gsub('Filter', '')) 
        end 
      end 
    end 

    def self.included base 
      base.extend ClassMethods 
    end 
  end 
end
class ShowFilter 
  include Filters::Base 

  filter :title do |title| 
    self.show.where(:title => title) 
  end 
end
于 2012-07-25T00:17:13.237 回答