Katie M
Katie M

Reputation: 1131

Rails Rake Task - How to Delete Records

I am trying to use a daily RAKE task to synchronize a users table in my app with a CSV file.

My import.rake task successfully imports records that aren't found in the table (find_or_create_by_username), but I don't know how to delete records from the table that are no longer found in the CSV file. What should I use instead of "find_or_create_by_username" to achieve this? Thanks in advance.

  #lib/tasks/import.rake

  desc "Import employees from csv file"
  task :import => [:environment] do

  file = "db/testusers.csv"

usernames = [] # make an array to collect names
CSV.foreach(file, headers: true) do |row|
    Employee.find_or_create_by_username({
      # Add this line:
      username = row[0]
      :username => username,
      :last_name => row[1],
      :first_name => row[2],
      :employee_number => row[3],
      :phone => row[4],
      :mail_station => row[5]
    }
    )
    # Collect the usernames
    usernames << username
    end
# Delete the employees (make sure you fire them first)
Employee.where.not( username: usernames ).destroy_all
end

Upvotes: 1

Views: 2725

Answers (3)

mjnissim
mjnissim

Reputation: 3112

usernames = [] # make an array to collect names
CSV.foreach(file, headers: true) do |row|
    username = row[0]
    Employee.find_or_create_by_username({
      :username => username,
      :last_name => row[1],
      :first_name => row[2],
      :employee_number => row[3],
      :phone => row[4],
      :mail_station => row[5]
    }
    )
    # Collect the usernames
    usernames << username
    end
# Delete the employees (make sure you fire them first)
Employee.where.not( username: usernames ).destroy_all

where.not will work with rails 4 of course.

Upvotes: 0

MrYoshiji
MrYoshiji

Reputation: 54882

You can achieve this by doing like the following:

#lib/tasks/import.rake
require 'csv'

desc "Import employees from csv file"
task :import => [:environment] do

    file = "db/users.csv"
    employee_ids_to_keep = []

    CSV.foreach(file, headers: true) do |row|
      attrs = {
        :username => row[0], :last_name => row[1], :first_name => row[2], 
        :employee_number => row[3], :phone => row[4],:mail_station => row[5]
      }
      # retrieves the Employee with username
      employee = Employee.where(username: attrs[:username]).first

      if employee.present? # updates the user's attributes if exists
        employee.update_attributes(attrs)
      else # creates the Employee if does not exist in the DB
        employee = Employee.create!(attrs)
      end

      # keeps the ID of the employee to not destroy it
      employee_ids_to_keep << employee.id 
    end

    Employee.where('employees.id NOT IN (?)', employee_ids_to_keep).destroy_all
end

Upvotes: 1

Philip Hallstrom
Philip Hallstrom

Reputation: 19879

Get a list of all ID's in the database and store them in a set. Then as you do your importing, remove valid employees from the set. Once you're done, any ID's left in the set need to be removed from the database.

Something like this...

existing_ids = Employee.pluck(:id).to_set
CSV.foreach(file, headers: true) do |row|
  employee = Employee.find_or_create_by.....
  existing_ids.delete(employee.id)
end     
Employee.destroy(*existing_ids.to_a) unless existing_ids.empty?

Upvotes: 0

Related Questions