Ruby 2.3.0, Rails 4.2.4, and actually using postgreSQL rather than SQLite
Updated for clarity
I have a large csv file (externally updated & downloaded daily) and wrote a method to update a Rails database table. I do not want the method to append all rows to the database without validating uniqueness, so I use this great solution (How do I make a column unique and index it in a Ruby on Rails migration?) with add_index.
I'm using a rake file to store the executable update code and I enter $ rake update_task in my terminal (which works IF the table has no duplicates with the imported csv rows). The problem with this is that the database ABORTS (rake aborted!) the rake when it encounters the first duplicate entry (ERROR: duplicate key value violates unique constraint).
What can I do to remove/not save any duplicates while avoiding aborting/failing? I cannot simply drop the database table and reload it each day. Here is the schema:
ActiveRecord::Schema.define(version: 20160117172450) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "tablename", force: :cascade do |t|
t.string "attr1"
t.string "attr2"
t.string "attr3"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "tablename", ["attr1", "attr2", "attr3"], name: "index_tablename_on_attr1_and_attr2_and_attr3", unique: true, using: :btree
end
and my rake task in lib/tasks/file_name.rake contents:
desc "Download data and update database table"
task :update_task => :environment do
u = CorrectClassName.new
u.perform_this
end
and CorrectClassName is in an .rb file in app/directory1:
class CorrectClassName
def perform_this
something = ClassWithUpdateCode.new
something.update_database
end
end
and ClassWithUpdateCode is in an .rb file in app/directory2:
require 'csv'
class ClassWithUpdateCode
def update_database
csv_update = File.read(Rails.root.join('lib', 'assets', "file_name.csv"))
options = {:headers => true}
csv = CSV.parse(csv_update, options)
csv.each do |row|
tm = TableModel.new
tm.attr1 = row[0]
tm.attr2 = row[1]
tm.attr3 = row[2]
tm.save # maybe I can use a different method or if statement here?
end
end
end
Update: @Kristan's solution works below, but here is where to put the begin/rescue/end handling:
In the .rb file in app/directory2:
require 'csv'
class ClassWithUpdateCode
def update_database
csv_update = File.read(Rails.root.join('lib', 'assets', "file_name.csv"))
options = {:headers => true}
csv = CSV.parse(csv_update, options)
csv.each do |row|
tm = TableModel.new
begin
tm.attr1 = row[0]
tm.attr2 = row[1]
tm.attr3 = row[2]
tm.save
rescue ActiveRecord::RecordNotUnique
end
end
end
end