0

我想用从外部 API 接收的值初始化检索到的对象中的一些属性。after_find并且after_initialize回调对我不起作用,因为这样我必须为每个接收到的对象调用 API,这非常慢。我想要以下内容:

class Server < ActiveRecord::Base
  attr_accessor :dns_names
  ...
  after_find_collection do |servers|
    all_dns_names = ForeignLibrary.get_all_dns_entries
    servers.each do |s|
      s.dns_names = all_dns_names.select{|r| r.ip == s.ip}.map{|r| r.fqdn}
    end
  end
end

请注意,缓存不是解决方案,因为我需要始终拥有当前数据,并且数据可能会在应用程序之外更改。

4

1 回答 1

1

您需要一个类方法来增强使用您的数据找到的每个服务器。所以,像:

def index
  servers = Server.where(condition: params[:condition]).where(second: params[:second])
  @servers = Server.with_domains_names(servers)
end

class Server
  def self.with_domain_names(servers)
    all_dns_names = ForeignLibrary.get_all_dns_entries
    servers.each do |s|
      s.dns_names = all_dns_names.select{|r| r.ip == s.ip}.map{|r| r.fqdn}
    end
  end
end

这样,ForeignLibrary.get_all_dns_entries唯一的运行一次,您可以使用这些额外信息来增强您的服务器。

如果您想在每次初始化服务器对象时都这样做,我会简单地委托而不是使用after_initialize. 因此,您可以有效地将所有 dns 条目存储在一个全局变量中,然后将其缓存一段时间。ForeignLibrary.get_all_dns_entries 调用。所以,它会是这样的:

class Server
  def dns_names
    ForeignLibrary.dns_for_server(self)
  end
end

class ForeignLibrary

  def self.reset
    @@all_dns_names = nil
  end

  def self.dns_for_server(server)
    all_dns_names.select{|r| r.ip == server.ip}.map{|r| r.fqdn}
  end

  def self.all_dns_names
    Mutex.new.synchronize do
      @@all_dns_names ||= call_the_library_expensively
    end
  end
end

(我在这里也使用了互斥锁,因为我们正在使用类变量 ||=)

要使用它,您将:

class ApplicationController
  before_filter do
    ForeignLibrary.reset #ensure every page load has the absolute latest data
  end
end
于 2013-06-09T23:23:55.730 回答