关于 ruby?? on rails:有没有办法将命名范围组合成一个新的命名范围?

关于 ruby?? on rails:有没有办法将命名范围组合成一个新的命名范围?

Is there a way to combine named scopes into a new named scope?

我有

1
2
3
4
class Foo  ActiveRecord::Base
  named_scope :a, lambda { |a| :conditions = { :a = a } }
  named_scope :b, lambda { |b| :conditions = { :b = b } }
end

我想要

1
2
3
class Foo  ActiveRecord::Base
  named_scope :ab, lambda { |a,b| :conditions = { :a = a, :b = b } }
end

但我更愿意以 DRY 的方式进行。我可以通过使用

获得相同的效果

1
 Foo.a(something).b(something_else)

但它不是特别可爱。


至少从 3.2 开始有一个聪明的解决方案:

1
2
3
scope :optional, -() {where(option: true)}
scope :accepted, -() {where(accepted: true)}
scope :optional_and_accepted, -() { self.optional.merge(self.accepted) }

好吧,我对 Rails 还是很陌生,我不确定你到底想要什么,但如果你只是为了代码重用,为什么不使用常规的类方法呢?

1
2
3
        def self.ab(a, b)
            a(a).b(b)
        end

您可以通过使用 *args 而不是 a 和 b 来使其更灵活,然后可能使其中一个或另一个可选。如果你被困在 named_scope 上,你不能扩展它来做同样的事情吗?

如果我对你想做的事情完全不满意,请告诉我。


是重用named_scope来定义另一个named_scope

为了您的方便,我把它复制在这里:

您可以使用 proxy_options 将一个 named_scope 回收到另一个中:

1
2
3
4
5
6
class Thing
  #...
  named_scope :billable_by, lambda{|user| {:conditions = {:billable_id = user.id } } }
  named_scope :billable_by_tom, lambda{ self.billable_by(User.find_by_name('Tom').id).proxy_options }
  #...
end

这样它可以与其他named_scopes链接。

我在我的代码中使用了它,它运行良好。

希望对你有帮助。


通过将其设为类方法,您将无法将其链接到关联代理,例如:

1
@category.products.ab(x, y)

另一种方法是应用此补丁来启用 named_scope:

的 :through 选项

1
2
3
named_scope :a, :conditions = {}
named_scope :b, :conditions = {}
named_scope :ab, :through = [:a, :b]

退房:

http://github.com/binarylogic/searchlogic

令人印象深刻!

具体来说:

1
2
3
4
5
6
7
class Foo  ActiveRecord::Base
  #named_scope :ab, lambda { |a,b| :conditions = { :a = a, :b = b } }
  # alias_scope, returns a Scope defined procedurally
  alias_scope :ab, lambda {
    Foo.a.b
  }
end

@PJ:你知道,我曾考虑过这一点,但因为我认为我以后无法像这样链接第三个命名范围,所以将其驳回:

1
Foo.ab(x, y).c(z)

但由于 ab(x, y) 返回 b(y) 将返回的任何内容,我认为链会起作用。让我重新思考显而易见的事情的方法!


推荐阅读