这个问题的背景是相当复杂和令人费解的,由于我正在寻找一个简单的答案,我将把它放在一边来解释我的问题,而不是提供这个假设的情况。
如果我有一个简单的ActiveRecord模型,叫做汽车,它的named_scopes如下:
named_scope :classic, :conditions => { :build_date <= 1969 }
named_scope :fast, lambda { |speed| :top_speed >= speed }忽略作用域本身,如果我调用:
Automobile.scopes这到底会返回什么呢?我在控制台中看到的是:
[ :classic => #<Proc:0x01a543d4@/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87>,
:fast => #<Proc:0x01a543d4@/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87> ]在我看来,这是一个键/值的数组,键是命名作用域的符号,值是指向ActiveRecord中的named_scope.rb文件的进程。
如果我想要给定的散列或Proc作为实际的命名作用域(对于:classic,我会收到":conditions => { :build_date <= 1969 }",我该如何找到它?
我正在写一个有条件地合并一些named_scopes的插件,在这方面我遇到了一些阻力。我目前正在使用以下内容来合并这些作用域:
scopes_to_use = Automobile.scopes
scoped_options = {}
Automobile.scopes.each do |scope|
scoped_options.safe_merge!(eval "Automobile.#{scope}(self).proxy_options")
end忽略我在这里所做的“正确性”,有没有更好的方法可以检索给named_scope的实际散列或Proc?我不喜欢在这个函数中使用'eval‘,如果我真的可以检索Hash或Proc,那么我就可以引入一些更强大的合并逻辑。任何关于这方面的想法都将不胜感激。谢谢。
发布于 2009-10-21 12:52:55
您在示例中定义的命名作用域都不会执行任何操作。他们在句法上是错误的。这可能会导致您可能遇到的问题。
假设示例是仓促创建的,并且您已经有了可用的示例。继续回答这个问题。
我该如何找到作为实际命名作用域的散列或进程呢?
Model.scopes[:scope_name]为您提供了进程。Model.send(:scope_name).proxy_options为您提供了提供给作用域的选项散列,例如:{ :conditions => ["build_date <= ?", 1969] }
要以编程方式检索模型中每个命名作用域的选项散列,您可以这样做:
scopes_to_use = Automobile.scopes
scoped_options = {}
Automobile.scopes.keys.each do |scope|
scoped_options.safe_merge!(Automobile.send(scope).proxy_options)
end对于需要参数的作用域,这并不能很好地工作,因为它们可能会引发异常。不幸的是,我想不出一个简单的方法来解决这个问题。
我能想到的最好的办法是测试proc的一致性,然后提供唯一的伪参数,并分析返回的代理选项,以找出发生了什么变化。但这需要大量的工作,因为任何命名作用域的数量都是-2。在检索参数时,你能做的最好的就是调用proc,修复一个参数错误,并解析它以获得预期的一个或多个参数。然后使用该数量的伪参数。
整个过程需要一个救援块和一些评估魔法才能起作用。这是在您可以处理用于安全合并的proxy_options散列之前。
简而言之,你会想要做一些类似的事情,它不是很漂亮,但它是有效的:
scopes_to_use = Automobile.scopes
scoped_options = {}
Automobile.scopes.each do |scope,proc|
next if scope == :scoped
number_of_args = 1
begin
scoped_options.safe_merge! Automobile.send(scope, "#{scope}_argument_1").proxy_options
rescue
$!.to_s.match /(\d+)\)$/
number_of_args = $1.to_i
puts number_of_args
end
scoped_options.safe_merge!(Automobile.send(scope, *(1..number_of_args).map{|i| "#{scope}_argument_#{i}"}.proxy_options)
end这应该是安全的,因为proxy_options既不执行SQL,也不进行任何类型检查。
https://stackoverflow.com/questions/1597581
复制相似问题