在我的Rails应用程序中,我正在做两件事 - 将Active Record结果与从外部API的JSON响应构建的数组进行比较。
第一步是检查数据库中的结果而不是API中的结果,我按如下方式执行:
def self.orphaned_in_db
db_numbers = self.find(:all).map{|x| x.number}
listed_numbers = self.all_telco.map{|x| x.number} # gets JSON from API
orphaned_numbers = db_numbers - listed_numbers
orphaned_results = self.find_all_by_number(orphaned_numbers)
return orphaned_results
end
这是新版本,因为旧版本在过去几周的结果集显着增加之后花了太长时间。
# def self.orphaned_in_db
# old version
# db_numbers = self.find(:all)
# listed_numbers = self.all_telco
# orphaned_numbers = []
# db_numbers.each do |db|
# scan = listed_numbers.select{ |l| l.number == db.number}
# orphaned_numbers.push(db) if scan.empty?
# end
# return orphaned_numbers
# end
我现在发现做与此相反的方法很棘手 - 在API数组中查找不在我的数据库表中的数字。
def self.orphaned_in_telco
db_numbers = self.find(:all).map{|x| x.number}
all_numbers = self.all_telco
listed_numbers = all_numbers.map{|x| x.number}
orphaned_numbers = listed_numbers - db_numbers
orphaned_results = # how to filter all_numbers by orphaned_numbers?
return oprhaned_results
end
再一次,旧方法现在无法工作,因为它太慢了:
# def self.orphaned_in_telco
# original, inefficient way
# db_numbers = self.find(:all)
# listed_numbers = self.all_telco
# orphaned_numbers = []
# listed_numbers.each do |l|
# scan = db_numbers.select{ |db| l.number == db.number}
# orphaned_numbers.push(l) if scan.empty?
# end
# return orphaned_numbers
# end
我发现这很难,因为它是相同的视图和部分之前用于显示这些孤立的数字(两次迭代)但它是遗留代码所以我从来没有看到它在行动中工作但我只是困惑如何它之前使用Active Record结果和正常数组工作。
视图只是:
<%= render :partial => 'list_item', :collection => @telco_numbers ) %>
其中@telco_numbers
设置为上述方法的返回值。 (@telco_numbers = TelcoNumber.orphaned_in_telco params[:page]
)
部分内容如下:
<tr>
<td>
<%= (link_to list_item.organisation.name.truncate(30), :controller => 'organisation', :action => 'update', :id => list_item.organisation.id) if list_item.organisation %>
</td>
<td class="centre"> <%= link_to ((list_item.countrycode == "44" ? Telco.format_uk_number(list_item.number) : "+#{list_item.countrycode} #{list_item.number}")), {:action => 'update', :id => list_item.id} %></td>
<td class="centre"><%= list_item.route_technology %></td>
<td><%= list_item.route_destination if list_item.route_destination %></td>
<td class="centre">
<% if !list_item.new_record? %>
[ <%= link_to 'Edit', {:action => 'update', :id => list_item.id} %> ]
<% else %>
[ <%= link_to 'Add New', {:action => 'update', :telco_number => list_item.attributes } %> ]
<% end %>
</td>
据我所知,对于我尝试修复的版本而不是Edit
操作,它会有一个Add New
链接,因为它不在我的数据库表中,所以我我只想弄清楚如何重构低效版本,以便它仍然可以使用共享视图。
如果有帮助,JSON API响应的格式为:
[{"country_code":"44","number":"1133508889","block":null,"type":"Legacy","SMS":"0"},
因此,只有country_code
和number
对应于我的数据库表中的列,其余部分不是必需的,因此部分中的if
语句只显示某些参数(如果它们是可用。
更新
按照Chris Vo的建议将方法更改为以下方法后,它最终会在花费很长时间后才能完成,但它仍然不太正确。
def self.orphaned_in_telco
# original, inefficient way
db_numbers = self.find(:all)
listed_numbers = self.all_telco
orphaned_numbers = listed_numbers - db_numbers
orphaned_results = []
orphaned_numbers.each do |n|
item = self.new()
item.id = n
orphaned_results.push(item)
end
return orphaned_results
end
我的视图html表中的数字列只包含+
字符,而Add New
链接没有countrycode
和number
网址参数的任何值(链接网址是正确的,所有参数都在查询字符串中,但它们都是空的。)
我的模型中的一些方法:
def self.max_search_results
return @@max_search_results
end
#for pagination
def self.per_page
20
end
def self.some_telco(per_page, page = 1)
page = 1 if page.nil?
api_call = TelcoApiv3.new("post", "/numbers/#{TelcoApiv3.account_id}/allocated/all")
listed_numbers = TelcoApiv3.poll(api_call.response["link"])
return listed_numbers.collect do |ln|
ln.store("countrycode", ln["country_code"])
TelcoNumber.new ln
end
end
def self.all_telco(page = 1)
listed_numbers = some_telco(@@max_nlist_results, page)
if listed_numbers.length == @@max_nlist_results
return listed_numbers.concat(all_telco(page + 1))
else
return listed_numbers
end
end
答案 0 :(得分:2)
但首先你要减少数据库调用。
self.find(:all) #stupid slow
我会用
指出你正确的方向self.where('number NOT IN (?)', array_of_phone_numbers)
这将找到所有不在json数据中的记录。
答案 1 :(得分:2)
对于orphaned_in_telco
方法,在找到orphaned_numbers
后,为该集合中的每个数字创建模型实例然后将其推送到表中以返回它们,该怎么办...或至少在那个方向的东西。 e.g。
orphaned_results = []
orphaned_numbers.each do |n|
item = self.new()
item.id = n
orphaned_results.push(item)
end
return orphaned_results
然后在您拨打Add new
时从部分内容中,您只需要在该实例上调用save
。
这样你就不会遇到部分Active Record和数组的问题,因为你将返回一个Active记录实例数组。
另外,我对加速事情的建议是使用哈希来存储密钥/数字。
希望它有所帮助!
<强>更新强>
为了获得国家代码并加快处理速度,我将继续提出我的哈希建议:
所以,让我们从最初的实施开始:
#this returns everything from the API
all_numbers = self.all_telco
#this returns a Hash in the form {:number => :country_code}
listed_numbers = Hash[all_numbers.map{|x| [x.number,x.country_code]}]
#so now you can do
orphaned_numbers = listed_numbers.keys - db_numbers
orphaned_results = []
orphaned_numbers.each do |n|
item = self.new()
item.number = n
item.countrycode = listed_numbers[n]
orphaned_results.push(item)
end
return orphaned_results
这应该给它一个提升,并将country_code发送到正面。