通过ActiveRecord访问SQL计算列

5
我有一个名为Person模型,其中包含代表出生日期(birth_date)的属性。
我还有一个名为age()的方法,用于计算该人的当前年龄。
现在,我需要根据该人的年龄运行查询,因此我已经将age()的逻辑复制为MySQL中的计算列。
我无法确定如何使此附加列成为模型默认选择语句的一部分。
我希望能够访问年龄,就像它是Person模型的本机属性一样,以执行针对其的查询并在我的视图中访问该值。
这可能吗,还是我想错了?
我认为我可以通过default_scopescope定义其他字段,但是这些方法似乎只识别现有字段。 我还尝试过将default_scopeattr_assessor配对使用。
我考虑过的可能解决方法,但不想使用的是:
  • 创建一个名为age的实际属性,并通过回调填充。 日期始终在变化,因此这显然是不可靠的。

  • 在ActiveRecord中复制age()的逻辑,并在作为where条件的范围中使用。 这将实现我所需的内容,但感觉并不很DRY。

  • 我已经缓存了age()方法的结果。 我最感兴趣的是在where子句中使用该字段的能力。

必须有一种通过SQL定义动态字段的方法,我可以通过模型默认访问这些字段。
任何帮助都将不胜感激。
Rich
更新:
我尝试利用范围的失败示例:
default_scope :select => "*, 2 as age"

attr_accessor :age

age是空白的,我认为这是因为作用域只涉及限制而不是扩展。


1
请展示一些代码。你是否为额外的属性设置了一些别名,例如 select('expression AS alias') - taro
@taro,我已经添加了一个例子。 - kim3er
我认为不需要 attr_accessor 声明。 - taro
1
很好,但我不在乎奖品 :) - taro
1
@kim3er:你可以在Rails API中了解有关命名范围中lambda函数的内容。对于你的问题,可以使用以下代码:scope :age, lambda {|age| :conditions => ["age(birch_date) > ?", age] }。或者只需使用许多可能性之一来计算此范围内的实际年龄。 - arnep
显示剩余6条评论
2个回答

4

kim3er,你的问题解决方案很简单。按照以下步骤操作:

从你的模型中删除 attr_accessor :age。你不需要它。

Person 模型中保留默认范围:default_scope :select => "*, 2 as age"

最后打开控制台并尝试执行

p = Person.first
p.age
=> 2

当您使用 as 定义 select 时,Rails 将自动为实例添加这些方法!因此,对于您的问题的答案是:

必须有一种通过 SQL 定义动态字段的方式,我可以通过模型默认访问它们。

即:

Rails


谢谢Gerry。@taro已经在上面的评论中回答了我的问题,但我非常感谢您提供的额外背景信息,所以我会将问题标记为已解决。 - kim3er

1

虽然我不是专家,但看起来你想要:

class Person < ActiveRecord::Base

scope :exact_age, lambda { |a| where('age = ?', a) }
scope :age_gt, lambda { |a| where('age > ?', a) }

话虽如此,我刚开始研究Arel,看起来相当不错


+1 感谢 @Michael K Madison,Arel 看起来非常不错,我会去看看的。 - kim3er
谢谢。还可以看看Metawhere,似乎更容易! - Michael K Madison

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接