Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rake / rails .save! not updating database

I am trying to save changes to my database trough a rake task.

In my rake task I do something like:

namespace :parts do
  desc "Update Parts table, swap names in title"
  task :swap => :environment do
    Part.swap
  end
end

In my Part class I do

def self.swap
  Part.all.each do |part|
    if (part.title =~ REGEX) == 0
      part.title.gsub! REGEX, '\2 \1'
      puts part.title
      part.save!
    end
  end
end

However, this does not save the part. The save! does return true. the puts part.title does return the value I want.

If I call

Part.update(part.id, title: part.title)

The database updates properly. Why is this? Am I doing something wrong in my loop? I am working with Rails 3.1.3, Rake 0.9.2.2 and MySQL2 0.3.7

like image 771
Benjamin Udink ten Cate Avatar asked Jan 02 '12 06:01

Benjamin Udink ten Cate


1 Answers

It's because the way ActiveRecord detects that attributes are changed is through the setter. Therefore, if you use gsub! on an attribute, ActiveRecord doesn't know it needs to update the database.

You'll probably have to do this:

part.title = part.title.gsub REGEX, '\2 \1'

Update from comment

Also, if you try to assign title to another variable and then gsub! it won't work either because it's the same object (code from my project, variable names different).

ruby-1.9.3-p0 :020 > t = p.name
 => "test" 
ruby-1.9.3-p0 :023 > t.object_id
 => 70197586207500 
ruby-1.9.3-p0 :024 > p.name.object_id
 => 70197586207500 
ruby-1.9.3-p0 :025 > t.gsub! /test/, 'not a test'
 => "not a test" 
ruby-1.9.3-p0 :037 > p.name = t
 => "not a test" 
ruby-1.9.3-p0 :026 > p.save
   (37.9ms)  BEGIN
** NO CHANGES HERE **
   (23.9ms)  COMMIT
 => true 

You have to .dup the string before modifying it.

ruby-1.9.3-p0 :043 > t = p.name.dup
 => "test" 
ruby-1.9.3-p0 :044 > t.gsub! /test/, 'not a test'
 => "not a test" 
ruby-1.9.3-p0 :045 > p.name = t
 => "not a test" 
ruby-1.9.3-p0 :046 > p.save
   (21.5ms)  BEGIN
   (20.8ms)  UPDATE "projects" SET "name" = 'not a test', "updated_at" = '2012-01-02 07:17:22.892032' WHERE "projects"."id" = 108
   (21.5ms)  COMMIT
 => true 
like image 102
AndrewF Avatar answered Oct 18 '22 20:10

AndrewF