Rails 3:如何编写DRYer范围

时间:2011-05-10 21:12:11

标签: ruby-on-rails-3 activerecord

我发现自己在两个地方编写了非常相似的代码,一次在模型上定义(虚拟)布尔属性,一次定义范围以查找与该条件匹配的记录。实质上,

scope :something, where(some_complex_conditions)

def something?
  some_complex_conditions
end

一个简单的例子:我正在为俱乐部会员建模; Member支付Fee,仅在某个year内有效。

class Member < ActiveRecord::Base
  has_many :payments
  has_many :fees, :through => :payments

  scope :current, joins(:fees).merge(Fee.current)

  def current?
    fees.current.exists?
  end
end

class Fee < ActiveRecord::Base
  has_many :payments
  has_many :members, :through => :payments

  scope :current, where(:year => Time.now.year)

  def current?
    year == Time.now.year
  end
end

是否有DRYer方法来编写使用虚拟属性的范围(或者,确定模型是否与范围的条件匹配)?

我对Rails很陌生,所以请指出我做的事情是否愚蠢!

3 个答案:

答案 0 :(得分:1)

这不是问题的答案,但是你的代码有一个错误(如果你在生产中使用类似的东西):Time.now.year将返回服务器启动的年份。您希望在lambda中运行此范围,以使其按预期运行。

scope :current, lambda { where(:year => Time.now.year) }

答案 1 :(得分:0)

是的,您可以在范围中使用一个或多个带lambda的参数。假设您有一组项目,并且想要取回那些“Boot”或“Helmet”:

  scope :item_type, lambda { |item_type|
    where("game_items.item_type = ?", item_type )
  } 

您现在可以执行game_item.item_type('Boot')以仅获取靴子或game_item.item_type('Helmet')以仅获取头盔。这同样适用于您的情况。您可以在范围中使用参数,以便以DRYer方式检查同一范围内的一个或多个条件。

答案 2 :(得分:0)

不,没有更好的办法去做你想做的事情(除了记下Geraud的评论)。在您的范围内,您将定义一个类级别过滤器,该过滤器将生成用于限制查找程序返回结果的SQL,在您定义要在此类的特定实例上运行的实例级别测试的属性中。

是的,代码类似,但它在不同的上下文中执行不同的功能。

相关问题