如何在Ruby中捕获并忽略ActiveRecord :: RecordNotUnique异常

时间:2013-03-13 03:08:11

标签: ruby-on-rails ruby rescue

我每天都运行ruby脚本作业,用于将数据从一个表加载到另一个表,直到源表中找到重复的键记录,因为该表没有约束。我的目标表拒绝了那些记录,因为目标表对列具有主键约束(head_date,center_id,site_url)。我的程序刚停止并在命令行上显示以下错误。 :-(

in `async_exec': PG::Error: ERROR:  duplicate key value violates unique constraint "tst_data_pkey" (ActiveRecord::RecordNotUnique)

我可以预期源表会有其他令人讨厌的记录。在捕获此活动记录异常后,如何继续处理并转到下一条记录?

以下是我的更新/插入的代码:

class SiteSection < ActiveRecord::Base

  SiteSection.establish_connection(
        :adapter  => 'postgresql',
        :host     => 'hoster-of-hosts.com',
        :database => 'super-inven',
        :username => 'user',
        :password => 'pass'
                      )
  self.table_name = 'master.target_tbl'  # << insert into this table
end

conn.query("select * from source_tbl") do |row|
  siteData = SiteSection.find_or_initialize_by_head_date_and_center_id_and_site_url(row[:date_c], row[:com_id], row[:site_link])

  siteData[:head_date]      = row[:date_c]
  siteData[:center_id]     = row[:com_id]
  siteData[:site_url]          = row[:site_link].nil? ? 'unknown' : row[:site_link]
  siteData[:people_cnt]      = row[:persons].nil? ? 0 : row[:persons]
  siteData[:ips]     = row[:ip_adds].nil? ? 0 : row[:ip_adds]

  siteData.save
i = i+1
puts "finished: #{i}" if i % 10000 == 0
end
conn.close

2 个答案:

答案 0 :(得分:3)

您可以使用

begin

rescue => e

end
像这样:

class SiteSection < ActiveRecord::Base

  SiteSection.establish_connection(
        :adapter  => 'postgresql',
        :host     => 'hoster-of-hosts.com',
        :database => 'super-inven',
        :username => 'user',
        :password => 'pass'
                      )
  self.table_name = 'master.target_tbl'  # << insert into this table
end

conn.query("select * from source_tbl") do |row|
  siteData = SiteSection.find_or_initialize_by_head_date_and_center_id_and_site_url(row[:date_c], row[:com_id], row[:site_link])

  siteData[:head_date]      = row[:date_c]
  siteData[:center_id]     = row[:com_id]
  siteData[:site_url]          = row[:site_link].nil? ? 'unknown' : row[:site_link]
  siteData[:people_cnt]      = row[:persons].nil? ? 0 : row[:persons]
  siteData[:ips]     = row[:ip_adds].nil? ? 0 : row[:ip_adds]

  begin
    siteData.save
  rescue => e
    puts e.message
    puts "Error happened but I'll just keep chuggin along"
  end
i = i+1
puts "finished: #{i}" if i % 10000 == 0
end
conn.close

rescue => e期待收到错误。它会通过不让它冒泡而吞下这个错误。您的代码将继续运行,而不会导致崩溃。

答案 1 :(得分:-1)

如果你有唯一的密钥,你应该使用它 - 像这样:

i = 0
puts 'loading records'
conn.query("select * from source_tbl") do |row|
  rec = SiteSection.where(
    :head_date => row[:date_c],
    :center_id => row[:com_id],
    :site_url => (row[:site_link] || 'unknown')
  ).first_or_initialize

  rec.people_cnt = (row[:persons] || 0)
  rec.ips => (row[:ip_adds] || 0)

  rec.save!

  i += 1
  print '.' if i % 10000 == 0
end
puts "done\ntotal records: #{i}"

这样您将保存记录(新)或更新记录(如果找到)。如果你没有改变你的话,那么ActiveRecord::RecordNotUnique不应该在这里!