批量搜索named_scope

时间:2014-05-27 04:51:54

标签: ruby-on-rails ruby-on-rails-2

这是由其他人编写的现有代码,我正在尝试增强它。我是一名从事Ruby on Rails的java开发人员,所以要体谅他人。

我有这样的实体

User 

交付实体,

Delivery 
belongs_to :user 

named_scope :for_abcs, :conditions => {'deliveries.xyz_type' => ['Xyz1', 'Xyz2']},

定义了许多这样的命名范围。

现在以这样的方式获取交付

 @deliveries = current_user.deliveries.send("for_abcs").with(:xyz, :sender, :receiver)
...
...
...
# few other  conditions added to @deliveries 

终于

@deliveries.sort(...)

这种方式占用了巨大的sql并且出现了性能问题。我想使用find_each,但find_each仅适用于Ruby on Rails中的Active Entity,如何在没有太多代码更改的情况下实现此目标(如果可能)

早些时候我曾经做过

Delevery.find_each 

无论在哪里

Delivery.find

现在我无法做到,因为它是一个数组,在Ruby on Rails中执行该操作的解决方法或正确的过程是什么。

编辑: 我尝试了什么:

deliveries_temp = []
@deliveries.find_each(:batch_size=>999) do |delivery_temp|
    deliveries_temp.push(delivery_temp)
end

这给了我错误

undefined method `find_each' for []:Array

type(@deliveries)返回ActiveRecord :: NamedScope :: Scope,rails版本2.3.18

2 个答案:

答案 0 :(得分:1)

find_each应该可以处理返回Relation(包括范围)的任何内容。

@deliveries = current_user.deliveries.for_abcs(:xyz, :sender, :receiver).find_each

更新

听起来你正在使用Rails 2.3。 find_each是2.3中的类方法,因此您需要一种从范围中提取条件并将其传递给find_each的方法。我找到了an article that looks promising,所以试一试:

Delivery.find_each(current_user.deliveries.for_abcs.scope(:find))

另外,我还不确定#with正在做什么。也许它应该是#includes

答案 1 :(得分:0)

经过一周的研究,通过查看源代码了解named_scopes。我明白了问题所在。 @deliveries是类ActiveRecord::NamedScope::Scope的对象。这个类没有find_each方法。所以我在Delivery模型文件中为限制和偏移写了一个新的named_scope,如下所示:

named_scope :limit_and_offset, lambda { |lim,off| { :limit => lim, :offset=>off } }

在此之后,我在一个循环中调用它来传递偏移和限制,例如。第一个循环有offset = 0,limit = 999,第二个循环有offset = 999,limit = 999。我将所有结果添加到一个emptry数组中。此循环继续,直到结果大小小于限制值。这是按照我想要的方式批量工作。

set = 1
total_deliveries = []
set_limit=999
original_condition = @deliveries
loop do
    offset = (set-1) * set_limit
    temp_condition = original_condition.limit_and_offset(set_limit,offset)
    temp_deliveries = temp_condition.find(:all)
    total_deliveries+= temp_deliveries
    set += 1
    break if temp_deliveries.size < set_limit
end
@deliveries = total_deliveries.sort do |a, b|