0

I have a rake task I need to run in order to sanitize (remove forward slashes) some data in the database. Here's the task:

namespace :db do
  desc "Remove slashes from old-style URLs"
  task :substitute_slashes => :environment do
    puts "Starting"
    contents = Content.all
    contents.each do |c|
      if c.permalink != nil
        c.permalink.gsub!("/","")
        c.save!
      end
    end
    puts "Finished"    
  end
end

Which allows me to run rake db:substitute_slashes --trace

If I do puts c.permalink after the gsub! I can see it's setting the attribute properly. However the save! doesn't seem to be working because the data is not changed. Can someone spot what the issue may be?

Another thing, I have paperclip installed and this task is triggering [paperclip] Saving attachments. which I would rather avoid.

jyoseph
  • 5,435
  • 9
  • 45
  • 64

2 Answers2

2

try this:

namespace :db do
  desc "Remove slashes from old-style URLs"
  task :substitute_slashes => :environment do
    puts "Starting"
    contents = Content.all
    contents.each do |c|
      unless c.permalink.nil?
        c.permalink = c.permalink.gsub(/\//,'')
        c.save!
      end
    end
    puts "Finished"    
  end
end

1.) Change != nil to unless record.item.nil? (I don't know if it makes a different, but I've never used != nil. You may want to use .blank? also judging by your code)

2.) Your gsub was malformed. The pattern must be between two / (/ stuff /). The \ is necessary because you need to escape the /.

3.) Bang (!) updates the object in place. I think your biggest issue may be that you are overusing !.

4.) You're also making this very inefficient... You are looking at every record and updating every record. Rails isn't always the best option. Learn SQL and do this in one line:

"UPDATE contents SET permalink = replace(permalink, '/', '');"

If you MUST use Rails:

ActiveRecord::Base.connection.execute "UPDATE contents SET permalink = replace(permalink, '/', '');"

Wow! One query. Amazing! :)

sethvargo
  • 26,739
  • 10
  • 86
  • 156
  • != nil is perfectly valid, also String#gsub can accept a string as its first argument. Your third point I do believe is correct. – gunn Dec 29 '10 at 02:01
  • like i said, i just wasnt sure, but im 100% sure that .nil? does :). im still not fully convinced with gsub - ive been unable to get gsub to work in irb on mac Ruby v 1.8.1. 3.) is definitely his problem, IN THIS CASE, but his biggest problem is that he's not using SQL. This is doable - as I published - in ONE statement which is SOOOO much faster that having an ActiveRecord object created for EACH item. He could at LEAST use .find_each instead! – sethvargo Dec 29 '10 at 02:04
  • Awesome. There are a lot of nuggets in here for a rails newb. I appreciate you taking the time to spell it all out. – jyoseph Dec 29 '10 at 02:12
  • no problem! :) TRUST me that your code will run much faster if you avoid ActiveRecord in Rake tasks – sethvargo Dec 29 '10 at 02:13
1

The next thing I would try would be

c.permalink = c.permalink.gsub("/","")

As for saving without callbacks, this stackoverflow page has some suggestions.

Community
  • 1
  • 1
gunn
  • 8,999
  • 2
  • 24
  • 24