【问题标题】:Ruby on Rails - Compare Active Record Result to Array Containing New Instansiated ObjectsRuby on Rails - 将 Activerecord 结果与包含新实例化对象的数组进行比较
【发布时间】:2013-11-18 12:46:54
【问题描述】:

在我的 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 url 参数没有任何值(链接 url 是正确的,所有参数都是在查询字符串中,但它们都是空的)。

我的模型中的一些方法:

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

【问题讨论】:

  • 有意思,数字列有索引吗?
  • @TheIrishGuy,刚刚检查,number 和其他 5 列已编入索引(包括主键)

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


【解决方案1】:

如果,对于orphaned_in_telco 方法,在找到orphaned_numbers 之后,您为该集合中的每个数字创建模型的实例,然后将其推送到表中以返回它们......或者至少是什么在那个方向。例如

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 Record 实例数组。

另外,我对加快速度的建议是使用哈希来存储键/数字。

希望对你有帮助!

更新

为了获得国家代码并加快速度,我将继续我的哈希建议:

那么,让我们从您的初始实现开始:

#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 发送到前端。

【讨论】:

  • 谢谢,现在运行,仍然很慢(DB 约为 60,000,API 约为 150,000)
  • 渲染后(仍然需要很长时间才能完成),我的视图 html 表中的数字列仅包含 + 字符,Add New 链接对于 countrycode 没有任何值和number url 参数,有什么想法吗?
  • 我更新了我的答案,基本上你没有从我的第一个答案中看到号码和国家代码,因为我使用id 而不是number 并且我没有在返回的中添加countrycode模型实例。希望它现在有更多帮助。享受吧!
  • 谢谢,马上试试。
  • 它似乎可以运行,但是当它完成时,它会出现 500 错误 - 即使在开发中也是如此。日志只是说:Status: 500 Internal Server Error closed MySQL connection 但似乎部分被渲染了成千上万次rendered telco_number/_list_item (1.4ms) x a bajillion。 Completed in 453933ms (View: 381934, DB: 393) | 200 OK [localhost/telco_number/list/TelcoOrphaned?page=1] /!\ FAILSAFE /!\ 11 月 20 日星期三 12:59:50 +0000 2013`
【解决方案2】:

但首先你要减少你的数据库调用。

 self.find(:all) #stupid slow

我会为你指明正确的方向

self.where('number NOT IN (?)', array_of_phone_numbers)

这将找到所有不在json数据中的记录。

【讨论】:

  • 谢谢,但在数据库中查找不在 api 中的数字是有效的(但我会接受这个建议并努力改进它),这与我正在努力的相反 - 获取数字在 API 中,但不在我的数据库中。
猜你喜欢
  • 1970-01-01
  • 2015-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-12
相关资源
最近更新 更多