展平ActiveRecord :: Relation实例的数组

时间:2013-12-20 15:33:51

标签: ruby-on-rails ruby ruby-on-rails-4

我想转换ActiveRecord::Relation个对象的嵌套数组,如下所示:

# Event is a ActiveRecord::Base derived class
r1 = [ [ Event.where(id: 1) ], Event.where(id: 1)]
# => [ [ #<ActiveRecord::Relation []> ], #<ActiveRecord::Relation[]> ]

成:

[#<ActiveRecord::Relation []>, #<ActiveRecord::Relation []> ]

Array#flatten旨在完美地完成此任务。不幸的是,它没有返回预期的结果:

r1.flatten # => []

Enumrable#map也不起作用:

r1.map{|m| m.limit(10) } # => []

Enumerable#flat_map会返回一个不同的结果:

r1.flat_map{|m| m.limit(10) } # => [ #<ActiveRecord::Relation []> ]

最后,循环遍历数组并推入另一个空数组会返回预期结果:

z = []
r1.each {|e| if e.is_a?(Array) then e.each{|x| z << x} else z << e end}
# => [#<ActiveRecord::Relation []>, #<ActiveRecord::Relation []> ]

导致这些差异的原因是什么?

我正在使用

  • ruby​​ 2.0.0p353(2013-11-22修订版43784)[x86_64-darwin13.0.0]
  • (通过RVM + Homebrew使用gcc构建)
  • Rails 4.0.2
  • MacOS X Mavericks

2 个答案:

答案 0 :(得分:2)

你得到的结果是因为当你枚举关系(或将它转换为数组)时,它不包含任何元素。

您可以在关系的打印输出中看到这一点,该关系在[]之前有>。如果其中有任何内容,您可以看到括号内的元素。

答案 1 :(得分:2)

当您执行.flatten时,该方法将触发由要执行的Relations包装的SQL查询。然后,查询结果将被展平。

在您的情况下,看起来两个查询都返回了一个空记录集,导致

r1 = [ [ Event.where(id: 1) ], Event.where(id: 1)]

评估为

r1 = [ [[]] , []]

该缩进变平为

[]

如果您尝试使用产生结果的范围的代码,那么您将看到flatten将返回记录数组。

为了展平范围,您需要一个像您一样的自定义方法。这是一个与illimitate级别一起使用的增强版本。

def flatten_scopes(scopes)
  scopes.inject([]) { |a,r| r.is_a?(Array) ? a += flatten_scopes(r) : a.push(r) }
end

flatten_scopes(r1)