我正在尝试通过rake任务保存对数据库的更改。
在我的佣金任务中,我做了类似的事情:
namespace :parts do
desc "Update Parts table, swap names in title"
task :swap => :environment do
Part.swap
end
end
在我的Part课程中我做了
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
但是,这并不能保存部分。 save!
确实返回true。 puts part.title
确实返回了我想要的值。
如果我打电话
Part.update(part.id, title: part.title)
数据库正确更新。为什么是这样?我在循环中做错了吗? 我正在使用Rails 3.1.3,Rake 0.9.2.2和MySQL2 0.3.7
答案 0 :(得分:17)
这是因为ActiveRecord检测到属性被更改的方式是通过setter。因此,如果对属性使用gsub!
,则ActiveRecord不知道它需要更新数据库。
您可能必须这样做:
part.title = part.title.gsub REGEX, '\2 \1'
另外,如果您尝试将标题分配给另一个变量,然后再为gsub!它不会起作用,因为它是同一个对象(来自我的项目的代码,变量名称不同)。
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
在修改之前你必须.dup
字符串。
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