从多个 ActiveRecord 查询创建 Ruby 哈希的有效方法

Efficient way to create a Ruby hash from multiple ActiveRecord queries

我正在尝试以优雅的方式解决问题。

我有一个 class:

class Pages < ActiveRecord::Base

  # Relations
  has_many :contents
  has_many :videos
  has_many :galleries
  has_many :surveys
  has_many :documents

end

我想创建这样的散列

{"videos"=>{:resource_type=>"Video", :resource_id=>2, :resource_name=>"Video di prova"}, "documents"=>{}, "contents"=>{}, "surveys"=>{}, "galleries"=>{}}

正在收集我协会中的记录。

我写了一个方法

def get_page_resources
    result = {}
    ['videos','galleries','documents','surveys','contents'].each do |r|
      if self.try(r)
        res_collection = {}
        self.send(r).each do |resource|
          res_collection.merge!(resource_type: resource.class.name)
          res_collection.merge!(resource_id: resource.id)
          res_collection.merge!(resource_name: resource.name)
        end
        result[r] = res_collection
      end
    end
    return result
  end

它有效,但我认为它很丑陋。 这个方法有没有更好的写法?

您可以通过将 res_collection 东西提取到这样的方法中来清理它:

def get_page_resources
  {
    videos:    res_collection(:videos),
    galleries: res_collection(:galleries),
    documents: res_collection(:documents),
    surveys:   res_collection(:surveys),
    contents:  res_collection(:contents)
  }
end

private

# this probably doesn't do what it was supposed to, but 
# just to give an impression without digging further into your
# code..
def resource_collection(resource)
  res_collection = {}
  self.send(resource).each do |resource|
    res_collection.merge!(resource_type: resource.class.name)
    res_collection.merge!(resource_id: resource.id)
    res_collection.merge!(resource_name: resource.name)
  end
  res_collection
end

我会将您的代码重构为以下代码,我认为它相当可读:

def resources
  %w(videos galleries documents surveys contents).map do |name|
    [
      name, send(name).map do |resource|
        {
          resource_type: resource.class.name,
          resource_id: resource.id,
          resource_name: resource.name
        }
      end
    ]
  end.to_h
end
  • get_ 开始一个方法是不惯用的 Ruby。只需在 return 之后命名该方法即可。 "page" 也不需要在名称中,因为这是 Pages 上的一个方法。 (顺便说一句,ActiveRecord 模型通常以单数命名而不是复数命名。)
  • %w() 比常规的引用词数组好一点。
  • r 不是 reader 友好的变量名。我使用 name,意思是 "resource name",因为从上下文中可以明显看出它是资源的名称。
  • 创建可枚举的模式,通过迭代另一个可枚举来构建它,然后 returning 它,通常可以使用 mapeach_with_object 变得更清晰和更短。
  • 将数组转换为散列时,通常方便的做法是 map 将其转换为 [key, value] 对的数组,然后将其转换为带有 .to_h 的散列。
  • try(r) 什么都不做,因为关联方法总是 return 一个真值。我删除了它。
  • self.调用赋值方法以外的方法时不需要
  • merge!可以用散列文字替换。
  • return 在方法的末尾是不必要的,而且不是惯用的。

重构很有趣,所以我按照说明回答了你的问题,但我同意 Nermin 的观点,你可能想研究一下序列化框架。