2009-10-20 90 views
3

的背景,這個問題是相當複雜和令人費解的,和我在尋找一個簡單的答案,我會離開它在解釋我的問題了路邊,而是提供這種假設的情況。ActiveRecord的named_scope,.scopes

如果我有一個簡單的ActiveRecord模型稱爲汽車,與像下面named_scopes:

named_scope :classic, :conditions => { :build_date <= 1969 } 
named_scope :fast, lambda { |speed| :top_speed >= speed } 

忽略的範圍自己,如果我打電話:

Automobile.scopes 

究竟會變成這樣回國?我在控制檯中看到的是:

[ :classic => #<Proc:[email protected]/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87>, 
    :fast => #<Proc:[email protected]/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87> ] 

這在我看來是鍵/值的數組,關鍵是指定範圍的象徵,是一個Proc指向named_scope.rb值ActiveRecord中的文件。

如果我要給出實際的命名範圍的散列或PROC(意爲:經典,我會收到「:條件=> {:build_date < = 1969年}」,我怎麼可能去尋找這個

我寫一個插件,有條件的合併一些named_scopes,和我對一些阻力關於這個跑起來 我目前使用以下合併這些範圍:

scopes_to_use = Automobile.scopes 
scoped_options = {} 
Automobile.scopes.each do |scope| 
    scoped_options.safe_merge!(eval "Automobile.#{scope}(self).proxy_options") 
end 

忽略了「正確性」我在這裏做什麼,有沒有更好的方式,我可以檢索實際的哈希或Proc給予named_scope?我不喜歡這個功能用「的eval」,如果我能實際檢索哈希或PROC,那麼我就可以推出一些更強大的組合邏輯。任何想法都將非常感激。謝謝。

回答

2

無論是命名範圍在您的例子定義願意做任何事。它們在語法上是錯誤的。這可能會導致您可能遇到的問題。

假設的例子是倉促建立和你有工作的人。談到答案。

我該如何去尋找散列或Proc作爲實際命名範圍。

Model.scopes[:scope_name]給你的過程。 Model.send(:scope_name).proxy_options爲您提供了選擇的散列賦予的範圍,即: { :conditions => ["build_date <= ?", 1969] }

以編程方式檢索每個命名的範圍在模型中的選項哈希,你可以這樣做:

scopes_to_use = Automobile.scopes 
scoped_options = {} 
Automobile.scopes.keys.each do |scope| 
    scoped_options.safe_merge!(Automobile.send(scope).proxy_options) 
end 

這並不爲工作很適合需要參數的範圍,因爲它們可能引發異常。不幸的是,我想不出一個簡單的方法。

我能想出是測試的PROC的元數,然後提供了獨特的虛擬參數和分析返回的代理選項要弄清楚什麼改變的最好的。但是這是很多工作,因爲任何命名範圍的參數都是-2。你可以在檢索的元數能做的就是調用PROC,營救參數錯誤並解析它預期的數字或參數。然後使用這個數量的虛擬參數。

整個過程需要一個救援塊和一些eval魔術才能工作。這就是你可以爲你的安全合併處理proxy_options哈希之前。

總之你會想要做一些接近這一點,它不漂亮,但它的工作原理:

scopes_to_use = Automobile.scopes 
    scoped_options = {} 
Automobile.scopes.each do |scope,proc| 
    next if scope == :scoped 
    number_of_args = 1 
    begin 
    scoped_options.safe_merge! Automobile.send(scope, "#{scope}_argument_1").proxy_options 
    rescue 
    $!.to_s.match /(\d+)\)$/ 
    number_of_args = $1.to_i 
    puts number_of_args 
    end 
    scoped_options.safe_merge!(Automobile.send(scope, *(1..number_of_args).map{|i| "#{scope}_argument_#{i}"}.proxy_options) 
end 

這應該是安全的,因爲proxy_options不執行的SQL,也不做任何類型檢查。

+0

此解決方案看起來可行,但比我想要的要更密集。我一直在尋找可以直接通過rails API使用的東西,但是如果沒有確切的東西存在,那麼我想我寧願找到一些其他解決方案來解決我的整體問題,而不是使用命名範圍的問題解決方案。感謝您的回答。它絕對回答了我的問題,但也爲我提出了更多。如果解決方案如此複雜,那麼我的目標肯定是錯誤的。 – Synthlabs 2009-10-21 16:36:56

+0

在這一點上並不重要,但我已經瞭解了*操作符。我編輯瞭解決方案來使用它來代替eval。 – EmFi 2009-12-04 21:12:38

+0

我遇到了同樣的問題,唯一的解決辦法就是這個,這很可悲。 – 2011-02-17 13:12:06