Kyl*_*cot 4 ruby ruby-on-rails ruby-on-rails-4 rails-activerecord
我的方法看起来像
class Student < ActiveRecord::Base
def self.search(options = {})
all.tap do |s|
s.where(first_name: options[:query]) if options[:query]
s.where(graduated: options[:graduated]) if options[:graduated]
# etc there are many more things that can be filtered on...
end
end
end
Run Code Online (Sandbox Code Playgroud)
在调用此方法时,我正在收回所有结果,而不是我期望的过滤集.好像我的tap功能没有像我期望的那样工作.这样做的正确方法是什么(没有赋值all给变量.如果可能,我想在这里使用块).
您可以轻松创建一个let功能:
class Object
def let
return yield self
end
end
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
all.let do |s|
s=s.where(first_name: options[:query]) if options[:query]
s=s.where(graduated: options[:graduated]) if options[:graduated]
# etc there are many more things that can be filtered on...
s
end
Run Code Online (Sandbox Code Playgroud)
tap和之间的区别let是tap返回对象并let返回块返回值.
tap不会为此工作。
all是一个ActiveRecord::Relation,一个等待发生的查询。all.where(...)返回一个新的 ActiveRecord::Relation新查询。但是,检查tap 的文档,您会发现它返回调用它的对象(在本例中all),而不是块的返回值。
即它的定义如下:
def tap
yield self # return from block **discarded**
self
end
Run Code Online (Sandbox Code Playgroud)
当你想要的只是:
def apply
yield self # return from block **returned**
end
Run Code Online (Sandbox Code Playgroud)
或者类似的东西。
这就是为什么您不断获取返回的所有对象,而不是查询结果的对象。我的建议是,您构建发送到的哈希值where,而不是链接where调用。就像这样:
query = {}
query[:first_name] = options[:query] if options[:query]
query[:graduated] = options[:graduated] if options[:graduated]
# ... etc.
all.where(query)
Run Code Online (Sandbox Code Playgroud)
或者一个可能更好的实现:
all.where({
first_name: options[:query],
graduated: options[:graduated],
}.delete_if { |_, v| v.empty? })
Run Code Online (Sandbox Code Playgroud)
(如果中间变量不符合您的口味。)