Ruby / Rails:构建嵌套对象数组的有效方法

时间:2017-03-22 10:51:28

标签: ruby-on-rails ruby performance nested self-referencing-table

我正在开发一个处理地方的API。我有一个构建为自引用的表,并包含parent_id列。到目前为止,我在该表中有144条记录。

我们的客户端应用需要接收嵌套的地区信息。由于我使用Rails,我首先尝试使用序列化程序的功能为我做这件事:

class LocalitySerializer < ActiveModel::Serializer
  attributes :id, :name, :postcode, :kind, :latitude, :longitude, :parent_id

  has_many :childrens
end

虽然它确实有效,但似乎效率不高。首先,日志显示对数据库的大量SQL查询。我当然试图使用类似Locality.includes(:childrens).all之类的东西来加载数据,但它不起作用而且没有效果(也许我做错了什么?)

我最终编写了一个递归函数,该函数获取了完整的局部列表(Locality.all),并检查每个元素的parent_id以嵌套它们。所以我删除了LocalitySerializer中的关联:

class LocalitySerializer < ActiveModel::Serializer
  attributes :id, :name, :postcode, :kind, :latitude, :longitude, :parent_id
end

并在其自己的序列化程序中单独构建:

class DictionarySerializer < ActiveModel::Serializer
  def attributes
    hash = super
    hash[:localities] = localities
    hash
  end

  private

  def localities
    Rails.cache.fetch('localities.json', expires_in: 7.days) do
      localities = ActiveModel::ArraySerializer.new(Locality.all, each_serializer: LocalitySerializer).as_json
      build_hierarchy(localities, [], nil)
    end
  end

  def build_hierarchy(source, target_array, n)
    source.select { |h| h[:parent_id] == n }.each do |h|
      h.except!(:parent_id)
      target_array << h.clone.merge(childrens: build_hierarchy(source, [], h[:id]))
    end

    target_array
  end
end

虽然这有点快,但它仍然很慢恕我直言。请注意,我在此处设置了一个低级缓存,以便在后续请求中更快。我实际上没有做任何基准测试(只是基于最终用户的感知),但如果它可以帮助任何人找出更快的生成方式,我会很乐意这样做。

0 个答案:

没有答案