有没有办法将命名范围合并到一个新的命名范围中?

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

提问人:James A. Rosen 提问时间:8/27/2008 最后编辑:strivedi183James A. Rosen 更新时间:8/17/2018 访问量:13804

问:

我有

class Foo < ActiveRecord::Base
  named_scope :a, lambda { |a| :conditions => { :a => a } }
  named_scope :b, lambda { |b| :conditions => { :b => b } }
end

我想要

class Foo < ActiveRecord::Base
  named_scope :ab, lambda { |a,b| :conditions => { :a => a, :b => b } }
end

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

 Foo.a(something).b(something_else)

但它不是特别可爱。

Ruby-on-Rails rails-activerecord 命名范围

评论

1赞 troelskn 8/13/2010
这种行为似乎在 Rails 中不是默认的。

答:

2赞 PJ. 8/28/2008 #1

好吧,我还是 rails 的新手,我不确定你在这里到底要做什么,但如果你只是想重用代码,为什么不使用常规的类方法呢?


        def self.ab(a, b)
            a(a).b(b)
        end
    

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

如果我完全偏离了你想做的事情,请告诉我。

评论

0赞 KARASZI István 2/18/2011
使用此解决方案时,它不会像普通范围那样表现为范围。例如,它不会在 .Model.scopes
0赞 James A. Rosen 8/28/2008 #2

@PJ:你知道,我曾经考虑过,但驳回了它,因为我认为我以后无法链接第三个命名的范围,如下所示:

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

但是,由于无论返回什么,我认为链条都会起作用。让我重新思考显而易见的方式!ab(x, y)b(y)

1赞 s-andringa 5/11/2009 #3

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

@category.products.ab(x, y)

另一种方法是应用此修补程序来启用 named_scope 的 :through 选项:

named_scope :a, :conditions => {}
named_scope :b, :conditions => {}
named_scope :ab, :through => [:a, :b]
1赞 Oinak 7/20/2010 #4

重用named_scope来定义另一个named_scope

为了方便起见,我把它复制到这里:

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

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赞 aceofspades 9/9/2010
需要注意的是,proxy_options仅返回最新命名作用域的作用域,因此不能针对另一个派生的命名作用域执行此操作
0赞 aceofspades 9/9/2010 #5

退房:

http://github.com/binarylogic/searchlogic

令人 印象 深刻!

具体来说:

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
15赞 Meta Lambda 5/29/2015 #6

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

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