2013-02-05 38 views
4

我正在爲我的網頁擴展搜索功能。變量作用域的定義和繼承

我看着ransack,但它缺少一些我需要的功能,使url查詢字符串非常長,並且有一些錯誤(報告)。

因此我開始實施自己的黑客攻擊。

首先我想介紹我的想法,事後我想問問如何解決我的問題,最後如果有其他方法可以改善這一問題。

的想法:

甲模型定義像這樣(此外,該模型是發動機內):

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

:名稱是定義查詢-PARAM使用例如這將是?q [name] =東西 我知道這不是完全通用的像ransack,但是...

:作爲建立正確的形式標籤。 :字符串用於text_field,:用於number_field的整數等等。我想進一步擴展它以實現爲關聯等自動生成集合。

現在該塊是一個簡單的使用範圍。 在構建複雜查詢(比如count()等)時,我遇到了幾個缺點與快速搜索。現在我可以在squeel中指定我自己的優化查詢。

我擴展了ActiveRecord :: Base來設置邏輯(全局的,不在引擎內部,我想在任何地方使用它)。 我定義了一個範圍:搜索,所以我可以像使用ransack一樣使用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 

現在的問題:

它大多與類的繼承做。但即使在閱讀並嘗試34它不起作用。

請看看範圍的第二行:搜索。

在那裏我打電話給我簡單的Proc我定義上面只包括「範圍」 這是爲了得到一個問題,自我返回「ActiveRecord :: Base」,而不是像「Post」或「Comment 」。

這是因爲範圍在繼承上的基類上調用,但我沒有找到任何解決方法。

由於在模型本身(例如Post)上調用search_for,所以返回的範圍模型是「正確的」。

有誰知道如何規避這個?

接下來的問題是,如何存儲「可搜索」範圍列表。我用@@變量。但是,因爲它們在每個子類中共享,這將是一個不可行的過程。 但是,它需要是靜態的,因爲search_for是在不初始化實例的情況下調用的(不是嗎?)

最後但並非最不重要的是,始終指定要在每個範圍上使用的基本模型以便我可以將它們鏈接在一起,這是非常可怕的。

有沒有其他的可能性來改善呢?

+0

請或不使用在您的文章簽名或標語(HTTP:/ /stackoverflow.com/faq#signatures)。 – meagar

回答

2

好吧,看來我終於明白了我自己把其他問題的其他答案放在一起。

型號:

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 

希望它會幫助一些人對同一問題的工作。

+0

同時,我將賞金/正確答案開放。也許有人想出了另一個更好的解決方案 – Noxx

+0

不知道我是否理解這個問題,但如果一個問題是「共享」類變量;你有沒有嘗試過類實例變量(或者他們叫什麼)?例如。 「階級」自我; attr_accessor:searchable_attributes; (僅在父類中是必需的),然後在內部將它們用作類中的@ searchable_attributes,或者用作self.class.searchable_attributes的實例方法。如果它們僅用於課堂中的內部使用,則可以跳過'attr_accessor'。 – 244an

1

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 
+0

另外,請注意,你要小心來自查詢字符串的東西,所以使用?插入語法來確保東西不能被注入: b.where(「name LIKE?」,「%#{q}%」) – loz

+0

as squeel-syntax is used,this is not applicable。在這種情況下,queque自動逃脫。 感謝ActiveSupport :: Concern和class_attribute提示,它變得更清晰一點,但是您將搜索範圍留給了一個完整的答案。 – Noxx