scope :type_with_arrays(arr), where(:type.in => arr).desc("created_at")
但这样不能传递参数,如何才能让 scope 携带参数?
自己来贴答案吧:
scope :admin, (lambda do |company_id|
{:conditions => ['company_id = ?', company_id]}
end)
再来一个更全面的参考:
class User
scope :by_age, lambda do |age|
joins(:profile).where('profile.age = ?', age) unless age.nil?
end
scope :by_name, lambda{ |name| where(name: name) unless name.nil? }
scope :by_email, lambda do |email|
joins(:profile).where('profile.email = ?', email) unless email.nil?
end
end
User.by_age(33).by_name(params[:name]).by_email(params[:email]).all
api 文档里是
scope :colored, lambda { |color| where(:color => color) }
如果是 ruby 1.9 就可以
scope :colored, ->(color) { where(:color => color) }
不过这个写法好怪。。。很难记忆
最后的实现办法:
scope :type_with_arrays, lambda { |arr| where(:_type.in => arr.map {|a| a.capitalize} ).desc("created_at") unless arr.empty? }
有点繁琐,但能用就管啦。
请看这个文档 http://apidock.com/rails/ActiveRecord/Scoping/Named/ClassMethods/scope
注意其中一段: class Shirt < ActiveRecord::Base scope :red, where(:color => 'red') end
The above calls to scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, in effect, represents the query Shirt.where(:color => 'red').
所以我一般都没有参数用 scope,有参数直接定义方法,也可可以传入多个参数,结构上也更容易读
def self.color(c) where(:color => c) end
两者等价,选择哪个看个人喜好了。
#16 楼 @IchiNiNiIchi #15 楼 @kevinhua 到底看过文档了么?先看的文档还是先到这里来提问? 如果是先看过文档了,那么到底文档什么地方不明白? 或者是不知道文档在那里?
如果你的问题中包含以上信息,我相信你不会被人说RTFM
想问下 scope 使用 Proc 实现,也可以用普通方法实现是吧?这种所谓的匿名函数有什么好处呢?感觉就像一个有静态变量的函数,也就是保存着状态的函数。
#21 楼 @IchiNiNiIchi 真不好意思,我已经把节点信息修改了。
#20 楼 @jiffies Scope并不是一个新东西,在 Rails2 时代就引入了,的确用 class_method 就可以实现 scope 的方法,Scope 的好处是返回一个 ActiveRecord::Relation
,然后你可以在返回对象上继续执行其他的 scope 操作,类似 category.posts.published
With these scopes, you can use every method previously covered such as where, joins and includes. All scope methods will return an ActiveRecord::Relation object which will allow for further methods (such as other scopes) to be called on it.
这里的 scope 上用的 Proc,我觉得不应当作匿名函数来理解,而应该理解成 Procedure。
Proc 用意是传入参数后,只有在调用 scope 的时候在调用的 context 中去对 Proc 进行求值 (eval),而不是在定义 Scope 的 context 下求值。因为 Scope 方法在定义后即被 Cache 了,所以任何传入的变量都需要通过 Proc 在调用时传入。
如果是用普通方法去实现,的确不需要用 Proc,但是也失去了通过 Proc 获得的灵活性,这就是 Ruby 语言灵活性所在呀。
#24 楼 @xds2000 这个问题太赞了,非常值得深思,研究并理解 AR 的 Scope 的设计理念。 我试着在没有深入研究的基础上,借花献佛用 José Valim 的话来回复你吧
You can chain scopes, but they will be evaluated at the moment you call them. That said, when you call started, it will execute the lambda, so it will have a frozen Time.now. In other words, chaining lambda scopes will likely give you the wrong result.
因为要 chain scopes,并 lazy evaluation,所以不能每次 dot 调用就立即执行并返回结果,所以借助 Proc 来封装一个计算的过程,直到最后需要的时候在执行,如果自行用self.method
级联的话,每次方法调用都会求值一次,没有 Lazy evaluation 的性能优势。
因为需要每次 dot 方法调用都返回 ActiveRecord::Relation
所以抽取这个模式成为通用模式,于是就变成了 named_scope,也就是后来的 scope 方法,用 scope 你不必自己管理方法的 return 结果。
上面两个“因为”是我对 Scoped 和 Proc 的灵活性的理解,还请有过研究的高人指正,呵呵。
我看到这个问题之后,打开 api.rubyonrails.org,搜索 scope,马上看到答案了,但由于那个页面是框架包着的,复制不到那个页面链接,所以就直接回了一句“看文档”,因为 Rails 只有两份文档:http://api.rubyonrails.org/ 和 http://guides.rubyonrails.org/,一个有目录,一个有搜索框,找起来并不难,这样的回答,不算偷懒吧?
#25 楼 @lgn21st 我翻了下 scope 方法的源码,我的理解是它把传入的 proc 定义成 model 的一个 class method 了?
# File activerecord/lib/active_record/scoping/named.rb, line 174
def scope(name, scope_options = {})
# 略去部分代码
scope_proc = lambda do |*args|
options = scope_options.respond_to?(:call) ? unscoped { scope_options.call(*args) } : scope_options
# 略去部分代码
end
singleton_class.send(:redefine_method, name, &scope_proc) # 注意 redefine_method 的使用
end
#1 楼 @hisea #2 楼 @iwinux #5 楼 @foxzool #12 楼 @vkill #16 楼 @IchiNiNiIchi #23 楼 @jiffies #24 楼 @xds2000 #25 楼 @lgn21st
感谢大家热烈讨论,首先我对我的过激言辞抱歉。
社区是一个多样性十足的地方,混社区的除了高手之外,更多的是新手。他们可能并不熟悉如何去看文档,在哪看文档,在文档里查找什么样的信息;看了文档也不一定清楚怎样用于实践。对于他们来说,有时一个 Rails 环境的设置,都会花费很多的时间。
所以新手们的提问,在高手看来不是什么问题,甚至不懈回答。但是也需要理解他们的需求,你的点滴指点,对于他们来说,就是成长为高手的支持和鼓励。
即使一个简单的问题,经过合适的指引和讨论,也可以成为精品。为后来者提供有用的信息,也为社区提供源源不断的内容。
scope :state_in, ->(states) { where('xxxs.state in (?)', states) if states } 这样不就得了么。。。我不知道为什么还要 lambda 查询 xxxs 的状态。参数就是 states!