【发布时间】:2012-11-30 22:37:00
【问题描述】:
在我正在制作的 gem 中,我想允许开发人员将我编写的类方法添加到模型中,我们称之为 interceptor,采用经典的 Devise 语法:
class User < ActiveRecord::Base
has_interceptor
end
这允许您调用User.interceptor,它返回一个Interceptor 对象,该对象通过Squeel gem 查询数据库来完成神奇的事情。都很好。
但是,我想首先找到一种允许开发人员确定拦截器执行的查询范围的优雅方法。这可以通过允许interceptor 接收ActiveRecord::Relation 并链接Squeel 来实现,否则就回退到模型上。此实现的工作原理如下:
# Builds on blank ARel from User:
User.interceptor.perform_magic
#=> "SELECT `users`.* FROM `users` WHERE interceptor magic"
# Build on scoped ARel from Relation:
User.interceptor( User.where('name LIKE (?)', 'chris') ).perform_magic
#=> "SELECT `users`.* FROM `users` WHERE `users`.`name` LIKE 'chris' AND interceptor magic"
这是有效的,但丑陋的。我真正想要的是:
# Build on scoped ARel:
User.where('name LIKE (?)', 'chris').interceptor.perform_magic
#=> "SELECT `users`.* FROM `users` WHERE `users`.`name` LIKE 'chris' AND interceptor magic"
本质上,我想“接入”ActiveRecord::Relation 链并窃取它的 ARel,然后将其传递到我的 Interceptor 对象中以在我评估它之前对其进行修改。但是我能想到的每一种方法都涉及到如此可怕的代码,我知道如果我实现它,上帝会杀了一只小猫。我不需要我手上的血。帮我救一只小猫?
问题:
增加了我的复杂性,
class User < ActiveRecord::Base
has_interceptor :other_interceptor_name
end
允许你调用User.other_interceptor_name,模型可以有多个拦截器。它运作良好,但使用method_missing 比平常更糟糕。
【问题讨论】:
-
似乎拥有
Interceptor子类Relation可能是要走的路,但在我想出更多Relations之前,我不想提交。 -
我没有答案,但是如果你让我链接 :interceptor 我会假设我可以将它放在链中的任何位置并且它仍然可以工作。真的吗?否则,让我将它用作作用域链的一部分可能会有点误导,但结果本身不是作用域......
-
它的作用类似于
.all或.first,因为它必然是链中的最后一个,因为它评估查询并返回非Relation。但它的行为类似于.where,因为它会在评估之前修改查询,因此必须在某个时候访问该链。 -
+1 表示“不杀小猫”。很好的问题标题!
-
我正在关注
ActiveRecord::Scoping'swith_scope,明天得去取回。
标签: ruby-on-rails ruby-on-rails-3 activerecord arel