【问题标题】:Rails 2.3 - implement dynamic named_scope using mixinRails 2.3 - 使用 mixin 实现动态 named_scope
【发布时间】:2011-09-13 09:24:39
【问题描述】:

我使用下面的method_missing实现给某个模型一个适应性强的named_scope过滤:

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_&lt;X&gt; 提供了这一点,但我试图超越我给出的示例,并为我的应用程序提供一些定制的过滤。我想让它可供选定的模型使用,而不必在每个模型类中粘贴这个 sn-p。我想过使用一个模块,然后将它混合到选择的模型中——我只是对语法有点含糊。

当错误开始堆积时,我已经做到了这一点(我这样做对吗?):

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

任何帮助都会很棒 - 谢谢。

【问题讨论】:

    标签: ruby-on-rails activerecord refactoring named-scope mixins


    【解决方案1】:

    实现这一目标的两种方法

    模块 GenericModule def self.included(base) base.extend 类方法 结尾 模块类方法 def methods_missing #.... 结尾 结尾 结尾 类 YourModel 包括通用模块 .. 结尾

    模块 GenericModule def method_missing #... 结尾 结尾 类 MyModel 扩展 GenericModule 结尾

    我建议使用第一个,它对我来说似乎更干净。作为一般建议,我会避免覆盖 method_missing :)。

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      您需要在包含您的 mixin 的类的上下文中定义范围。在 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-30
        • 2017-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多