Rails 3:如何编写 DRYer 范围
我发现自己在两个地方编写非常相似的代码,一次是在模型上定义(虚拟)布尔属性,一次是定义范围以查找与该条件匹配的记录。本质上,
scope :something, where(some_complex_conditions)
def something?
some_complex_conditions
end
一个简单的例子:我正在为俱乐部会员资格建模; 会员
支付费用
,该费用仅在特定年份
有效。
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
是否有一种更干燥的方法来编写使用虚拟属性的范围(或者,确定模型是否与范围的条件匹配)?
我对 Rails 还很陌生,所以请指出我是否做了一些愚蠢的事情!
I'm finding myself writing very similar code in two places, once to define a (virtual) boolean attribute on a model, and once to define a scope to find records that match that condition. In essence,
scope :something, where(some_complex_conditions)
def something?
some_complex_conditions
end
A simple example: I'm modelling a club membership; a Member
pays a Fee
, which is valid only in a certain 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
Is there a DRYer way to write a scopes that make use of virtual attributes (or, alternatively, to determine whether a model is matched by the conditions of a scope)?
I'm pretty new to Rails so please do point out if I'm doing something stupid!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这不是问题的答案,但您的代码有一个错误(如果您在生产中使用类似的东西):Time.now.year 将返回服务器启动的年份。您希望在 lambda 中运行此范围以使其按预期运行。
This in not an answer to the question, but your code has a bug (in case you use something similar in production): Time.now.year will return the year the server was started. You want to run this scope in a lambda to have it behave as expected.
不,没有更好的方法来完成您想要做的事情(除了注意 Geraud 的评论)。在您的范围内,您定义一个类级过滤器,它将生成用于限制查找器返回的结果的 SQL,在您定义要在此类的特定实例上运行的实例级测试的属性中。
是的,代码是相似的,但它在不同的上下文中执行不同的功能。
No, there's no better way to do what you're trying to do (other than to take note of Geraud's comment). In your scope you're defining a class-level filter which will generate SQL to be used in restricting the results your finders return, in the attribute you're defining an instance-level test to be run on a specific instance of this class.
Yes, the code is similar, but it's performing different functions in different contexts.
是的,您可以在作用域中使用一个或多个带有 lambda 的参数。假设您有一组物品,并且您想要取回“Boot”或“Helmet”:
您现在可以执行 game_item.item_type('Boot') 来仅获取靴子或 game_item.item_type('头盔')只获得头盔。这同样适用于你的情况。您可以在作用域中只包含一个参数,以便以一种更干燥的方式检查同一作用域上的一个或多个条件。
Yes, you can use one or more parameters with a lambda in your scopes. Suppose that you have a set of items, and you want to get back those that are either 'Boot' or 'Helmet' :
You can now do game_item.item_type('Boot') to get only the boots or game_item.item_type('Helmet') to get only the helmets. The same applies in your case. You can just have a parameter in your scope, in order to check one or more conditions on the same scope, in a DRYer way.