Reputation: 1640
I want to initialize some attributes in retrieved objects with values received from an external API. after_find
and after_initialize
callbacks won't work for me as this way I have to call the API for each received object, which is is quite slow. I want something like the following:
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
Please note that caching is not a solution, as I need to always have current data, and the data may be changed outside the application.
Upvotes: 0
Views: 73
Reputation: 40277
You'd want to have a class method that enhances each server found with your data. so, something like:
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
This way, the ForeignLibrary.get_all_dns_entries
only gets run once, and you can enhance your servers with that extra information.
If you wanted to do this every time you initialize a server object, I'd simply delegate rather than use after_initialize
. So you'd effectively store the all dns entries in a global variable, and then cache it for a period of time. ForeignLibrary.get_all_dns_entries call. So, it would be something like:
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
(I also used a mutex here since we are doing ||= with class variables)
to use it, you would:
class ApplicationController
before_filter do
ForeignLibrary.reset #ensure every page load has the absolute latest data
end
end
Upvotes: 1