我发现自己在两个地方编写了非常相似的代码,一次在模型上定义(虚拟)布尔属性,一次定义范围以查找与该条件匹配的记录。实质上,
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很陌生,所以请指出我做的事情是否愚蠢!
答案 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,在您定义要在此类的特定实例上运行的实例级别测试的属性中。
是的,代码类似,但它在不同的上下文中执行不同的功能。