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
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