变量范围定义和继承



我正在为我的网页开发一个扩展搜索功能。

我看了一下洗劫,但它缺乏我需要的一些功能,使url查询字符串很长,并且有一些错误(报告)。

因此,我开始实现我自己的破解。

首先,我想提出我的想法,然后我想善意地询问如何解决我的问题,最后是否有其他方法可以改进这一点。

想法:

一个模型定义了这样的东西(另外,模型在引擎内部):

module EngineName
  class Post < ActiveRecord::Base
    search_for :name, :as => :string do |b, q|
      b.where{name =~ "%#{q}%"}
    end
  end
end

:name是定义要使用的查询参数,例如这将是?q[名称]=某事我知道这不是像洗劫一样完全通用的,但是。。。

:按原样建立正确的表单标记。:字符串表示text_field,:integer表示number_field等等。我想进一步扩展它,以实现关联等集合的自动生成。

现在这个块是一个简单的作用域。我在构建复杂的查询时遇到了一些缺点(比如使用count()等)。现在我可以在scroll中指定我自己的优化查询。

我扩展了ActiveRecord::Base来设置逻辑(全局逻辑,而不是在引擎内部。我想在任何地方都使用它)。我定义了一个范围:search,这样我就可以像在transak中一样使用Model.search(param[q])。此外,我还试图保留一个由search_for调用定义的"可搜索"键列表。

class ActiveRecord::Base
@@searchable_attributes = Hash.new({})
def self.search_for(name, *opts, &search_scope)
  return unless search_scope
  @@searchable_attributes[name] = {
    :type => opts[:as],
    :condition => search_scope
  }
  unless @@searchable_attributes.has_key? :nil
    @@searchable_attributes[:nil] = Proc.new { scoped }
  end
end
scope :search, lambda {|q|
  next unless q.kind_of?(Hash)
  base = @@searchable_attributes[:nil].call
  q.each do |key, search|
    next unless base.class.searchable_attributes.has_key?(key)
    base = @@searchable_attributes[key][:condition].call(base, search)
  end
  base
}
end

现在的问题是:

这主要和类的继承有关。但即使在阅读并尝试了3、4之后,它也没有起作用。

请查看范围中的第二行:搜索。

在那里,我称之为我在上面定义的简单过程,它只包括"scoped"这是为了解决self返回"ActiveRecord::Base"而不是像"Post"或"Comment"那样的模型本身的问题。

这是因为作用域是在继承时在基类上调用的,但我没有找到任何解决方法。

当在模型本身(例如Post)上调用search_for时,返回的范围模型是"正确的"。

有人知道如何规避吗?

下一个问题是,如何存储"可搜索"范围的列表。我使用了@@变量。但由于它们在每个子类中都是共享的,所以这是不可能的。然而,它需要是静态的,因为在没有初始化实例的情况下调用search_for(不是吗?)

最后但同样重要的是,总是指定要在每个作用域上使用的基本模型,这样我就可以将它们链接在一起,这有点可怕。

还有其他可能改进吗?

好吧,我把其他问题的其他几个答案放在一起,似乎终于自己得到了。

型号:

module EngineName
  class Post < ActiveRecord::Base
    searchable
    search_for :name, :as => :string do |b, q|
     b.where{name =~ "%#{q}%"}
    end
  end
end

我的"插件"当前作为初始值设定项:

class ActiveRecord::Base
  def self.searchable
    include Searchable
  end
end
module Searchable
  def self.included(base)
    base.class_eval {
      @@searchable_attributes = Hash.new({})
      def self.search_for(name, opts)
        return unless block_given?
        @@searchable_attributes[name] = {
          :type => opts[:as],
          :condition => Proc.new
        }
      end

      # Named scopes
      scope :search, lambda {|q|
        next unless q.kind_of?(Hash)
        base = self.scoped
        q.each do |key, search|
          key = key.to_sym
          next unless @@searchable_attributes.has_key?(key)
          base = @@searchable_attributes[key][:condition].call(base, search)
        end
        base
      }
    }
  end
end

希望它能帮助其他人解决同样的问题。

Rails为class_attribute提供了一个助手。这提供了可继承的类属性,但允许子类"更改自己的值,并且不会影响父类"。然而,例如,使用[]=进行变异的哈希会影响父级,因此您可以确保在使用rubys继承方法进行子类化时生成新的副本

因此,您可以在基类上声明和初始化如下:

module Searchable
  extend ActiveSupport::Concern
  included do
    class_attribute :searchable_attributes
  end
  module ClassMethods
    def inherited(subclass)
      subclass.searchable_attributes = Hash.new({})
    end
    def search_for(name,opts)
      return unless block_given?
      searchable_attributes[name] = {
        :type => opts[:as],
        :condition => Proc.new
      }
    end
  end
end

请注意,我使用了ActiveSupport::Concern来获得更整洁的语法,用于直接在类上定义内容,以及在类中混合方法。然后你可以简单地将其添加到活动记录库中:

ActiveRecord::Base.send(:include, Searchable)

现在任何类都有自己的属性散列:

class Post < ActiveRecord::Base
  search_for :name, :as => :string do |b, q|
    b.where{name =~ "%#{q}%"}
  end
end

相关内容

  • 没有找到相关文章

最新更新