在我的Ruby on Rails项目中,我有一个邮件程序,它基本上准备了系统中为给定用户发生的事情的每日摘要。在邮件程序控制器中,我根据一些常见模式收集各种模型中的所有相关记录(在某个日期内,不是由该用户创作,未标记等),并且模型与模型之间存在细微差别。
这里涉及六个模型(并且正在计算),并且大多数模型具有某些事物的统一列名称(例如发布日期,或者是否由管理员标记项目)。因此,进入查询的'where
大致相同。条件有细微差别,但至少2或3个条件完全相同。我很容易假设模型之间可能存在更多相似的条件,因为我们刚刚开始使用该功能并且尚未找出数据的最终形状。
我基本上在每个模型上链接'where
'调用。让6行代码彼此如此接近让我感到恼火,到目前为止我的代码编辑器的右边都是如此,但却非常相似。令我害怕的是,在某些时候我们将不得不改变一个“核心”条件,同时修改那么多行代码。
我喜欢做的是将每个查询中的一组核心条件移动到某种Proc或其他任何类型,然后简单地在每个模型上调用它,就像作用域一样,然后继续'{{ 1}}'具有模型特定条件的链。就像每个模型上的where
一样。
我正在努力的是如何做到这一点,同时将代码保留在邮件程序中。我当然知道我可以在一个问题中声明一个复杂的范围,然后将它混合到我的模型中并使用该范围启动每个查询。然而,这种方式逻辑将从邮件程序转移到模型关注的未知领域,并且它将使每个模型复杂化,其范围目前仅在庞大系统中的一个小邮件程序中需要。此外,对于某些查询,查询需要用户模型的一组详细信息,我不希望每个模型都处理用户。
我喜欢通过lambdas(如scope
)在Active Record模型中定义范围的方式,并且正在寻找一种在模型类之外和我的邮件程序方法中使用类似语法的方法(可能使用{{ 1}}或类似的东西),但我没有找到这种方法的任何好例子。
那么,有可能实现吗?我可以在我的邮件程序方法中收集某个变量中的核心“scope :pending, -> { where(approved: [nil, false]) }
”调用,并将它们应用于许多模型,同时仍然可以继续tap
链吗?
答案 0 :(得分:1)
您可以执行以下操作:
@report_a = default_scope(ModelA)
@report_b = default_scope(ModelB)
private
def default_scope(model)
model.
where(approved: [nil, false]).
order(:created_at)
# ...
end
答案 1 :(得分:1)
Arel的美丽,ActiveRecord查询构建背后的技术,它使用普通的红宝石完全可以组合。
我是否理解你的问题,这是你想要做的?
def add_on_something(arel_scope)
arel_scope.where("magic = true").where("something = 1")
end
add_on_something(User).where("more").order("whatever").limit(10)
add_on_something( Project.where("whatever") ).order("something")
只需普通的红宝石方法即可,您不需要特殊的AR功能。因为AR范围已经可以组合。