2011-08-13 48 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

相关问题