如何在Rails中创建一个动态命名的方法?

时间:2011-08-13 23:19:50

标签: ruby ruby-on-rails-3

我的类中有一个方法,它接受一个数字参数。它看起来像这样:

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一样在Ruby中定义方法真的很棒:

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

但我想现在不太可能。有趣的东西!

2 个答案:

答案 0 :(得分: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错误将导致无限递归。要小心!

答案 1 :(得分:2)

您可以使用method_missing执行此操作,但这是一种危险的方法,可能会导致代码非常混乱。相反,怎么样

User.with_more_posts_than(10)

更干净(更容易使用和维护)。它仍然可以正确读取。

作为众多异议中的一个特定点,您不应将10转换为字符串并返回。这带来了一大堆新的潜在错误,您将在稍后处理这些错误。