Ruby on Rails - 将Activerecord结果与包含新实例化对象的数组进行比较

时间:2013-11-18 12:46:54

标签: ruby-on-rails ruby json activerecord ruby-on-rails-2

在我的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_codenumber对应于我的数据库表中的列,其余部分不是必需的,因此部分中的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链接没有countrycodenumber网址参数的任何值(链接网址是正确的,所有参数都在查询字符串中,但它们都是空的。)

我的模型中的一些方法:

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

2 个答案:

答案 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发送到正面。