3
\$\begingroup\$

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.

asked Apr 14, 2016 at 1:59
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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
answered Apr 19, 2016 at 9:20
\$\endgroup\$
1
  • \$\begingroup\$ 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! \$\endgroup\$ Commented Apr 22, 2016 at 2:46

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.