Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm using Rails 4.2.5, and I'd like to update existing records with a csv file with two fields: id,category. Where if the category field is blank, it defaults to misc.

Here's an example csv file:

id,category
123-123-123,0
123-123-124,1
123-123-125,
123-123-126,2

So, I've created some tasks, update_item_categories, and set_item_categories:

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

namespace :db do
  task :update_item_categories => :environment do
  categories = ['misc', 'food', 'drink']
  CSV.foreach('public/update/item_categories.csv', headers: true) do |row|
    row_hash = row.to_hash
    category = categories[row_hash['category'].to_i]
    unless Item.where(id: row_hash['id']).empty?
      item = Item.find(row_hash['id'])
      item.update_attributes(
        :category => category
      )
      item.save!
    end
  end

  task :set_item_categories => :environment do
    Item.where(category: nil).each do |item|
      item.update_attributes(category: 'misc')
      item.save!
    end
  end
end

I will definitely appreciate any advice on how this could be better written, and also whether this is even a good way to go about solving this problem.

share|improve this question
up vote 2 down vote accepted

Regarding the first task, you could save a couple of queries by modifying the code to look like this:

# ....

CSV.foreach('public/update/item_categories.csv', headers: true) do |row|
  row_hash = row.to_hash
  category = categories[row_hash['category'].to_i]

  item = Item.where(id: row_hash['id'])
  item.update_attributes!(category: category) unless item.nil?
end

# ....

You can retrieve the item once and perform update_attributes! without save!. update_attributes! saves the changes to the db using save! internally. Here's the source code (update_attributes! it's an alias for update!):

def update!(attributes)
  with_transaction_returning_status do
    assign_attributes(attributes)
    save!
  end
end

Regarding the second task, since you want to raise an exception in case of invalid record, you have to save each record individually but you can save some queries by finding records in batches. The code could look like this:

Item.find_each(category: nil) do |item|
  item.update_attributes!(category: 'misc')
end
share|improve this answer
    
Thanks! find_each came up in codereview on my PR, so I had changed that. Also, I don't have enough reputation to vote up, or mark as the answer, yet! – Drew Ogryzek Apr 22 '16 at 2:46

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.