【问题标题】:How to catch and ignore ActiveRecord::RecordNotUnique exception in Ruby如何在 Ruby 中捕获和忽略 ActiveRecord::RecordNotUnique 异常
【发布时间】:2013-03-13 03:08:10
【问题描述】:

我每天运行 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

【问题讨论】:

    标签: ruby-on-rails ruby rescue


    【解决方案1】:

    你可以用一个

    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 =&gt; e 期望捕获一个错误。它会通过不让它冒泡来吞下这个错误。您的代码将继续运行,不会出现异常崩溃。

    【讨论】:

    • 你确定它的异常需要围绕self.table_name = 'master.target_tbl'?这是为什么?我认为它应该围绕它实际插入的部分或 siteData.save 命令。请让我知道逻辑,以便我更好地理解..谢谢。
    • 是的,它会在save 上提出。固定
    【解决方案2】:

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

    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}"
    

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

    【讨论】:

    • 顺便说一句 - 如果您仍然有错误,您可以使用 begin ... rescue =&gt; e ... end 阻止。但是这里不应该有错误;)
    猜你喜欢
    • 1970-01-01
    • 2012-11-13
    • 1970-01-01
    • 2012-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-17
    • 2021-08-19
    相关资源
    最近更新 更多