2011-08-13 93 views
2

我在我的課程中有一個方法需要一個數字參數。它看起來是這樣的:如何在Rails中創建一個動態命名的方法?

def with_at_least_x_posts(min_posts) 
    self.where("posts_counter >= ?", min_posts) 
end 

我想提出的是採用該參數的名字裏面,而不是在括號中的方法,所以不是調用

User.with_at_least_x_posts(10) 

我可以打電話

User.with_at_least_10_posts 

這將需要被通過某種正則表達式機構限定該方法。我知道find_by方法就是這樣工作的(即find_by_some_column),所以應該可以嗎?

有人能告訴我如何實現在Ruby中1.9.2和Rails 3.1沒有挖掘到Rails核心,並找出爲自己節省了一些時間?

謝謝!


更新:在等待答案時,我一直在深入研究Rails核心。好像他們是在覆蓋的ActiveRecord::Base方法method_missing和委託定製的方法,以一個名爲DynamicFinderMatch模塊處理。有趣的東西! 將是非常好的,能夠在Ruby中定義這樣的方法:

def /with_at_least_[0-9]+_posts/ 
    x = $0 
end 

,但我想這是不是真的有可能在這個時間點。有趣的東西!

回答

3

您應該將一般的Ruby方法method_missing

def with_at_least_x_posts(min_posts) 
    self.where("posts_counter >= ?", min_posts) 
end 

def method_missing(sym, *args, &block) 
    begin 
    if sym.to_s =~ /with_at_least_(\d+)_posts/ 
     return send :with_at_least_x_posts, *(args.push($1.to_i)), &block 
    end 
    rescue NoMethodError => e 
    raise "Unable to find method: #{e.inspect}" 
    end 

    return super 
end 

中定義一個電話從這裏,你就可以打電話myObj.with_at_least_10_posts。搏一搏!你可以閱讀更多here

P.S.這在Ruby中很常見(這就是ActiveRecord所做的)。請注意,如果你得到一個錯誤的StackOverflow,這是因爲在method_missing提出了method_missing錯誤將導致infinate遞歸。要小心!

+0

Yeup!這確實是我的問題的正確答案,我會選擇它。但是,在你和@Peter之間討論之後,我已經決定在這種情況下它增加了一層不必要的複雜性。我只會去一個命名的範圍。謝謝! –

+0

我認爲這是正確的舉措。很高興知道這種方法的時候,但它是一個實際的解決方案。 – ghayes

+0

如果正則表達式不匹配,你不應該調用super嗎? – DGM

2

您可以用method_missing做到這一點,但是這是一個危險的方法,可以導致非常混亂的代碼。相反,如何

User.with_more_posts_than(10) 

這是更清潔(和更容易處理和維護)。它仍然正確讀取。

由於許多反對中一個特定的點,你不應該轉換10爲字符串和背部。這會帶來一系列新的潛在錯誤,您稍後需要處理。

+0

我同意它不是最乾淨/最清晰的代碼結構,但它在Rails社區中顯得非常常見。我們是否真的不鼓勵批發業務? – ghayes

+0

您可以考慮'method_missing'創建大量新方法。所以'find_by_name'就是這些方法之一。但與'with_at_least_1_posts','with_at_least_2_posts',....相比,'find_by_xxx'方法只有相當少的數量。顯然它是動態處理的,但它非常混亂。 – Peter

+0

好的,我同意。這種情況是任意的/不必要的。也就是說,這可能是OP正在處理的更大問題的一個虛擬版本。 – ghayes

相關問題