狡诈的concat方法
今天做一个小玩意儿,想用类似webistrano的构思,后台执行任务,前台显示进度。
于是在后台执行任务的时候 数据库产生一条 deployment的记录,deployment有log字段。
在执行任务的同时 把deployment的log字段中 添加 日志信息。
前台同时 定时读取deployment的信息,显示出来。
问题是 我在后台任务更新 log的时候,前台始终读不出来deployment的最新log。
调查半天,发现ActiveRecord::Base的一个bug。
我的代码是这样写的
def digui_add_file(struct, path, zip)
dup_path = path.dup
if struct["name"]
if dup_path.blank?
dup_path = struct['name']
else
dup_path << "/#{struct['name']}"
end
if struct["children"].present?
struct["children"].each do |child|
digui_add_file(child, dup_path, zip)
end
elsif struct["files"].present?
files = UploadFile.all(:conditions => ["id in (?)", struct["files"]])
files.each do |file|
file_path = dup_path + "/" + file.filename
#log info
@deploy.log << "add: #{file_path}\n"
@deploy.save
zip.add(file_path, file.url)
end
else
#log info
@deploy.log << "mkdir: #{dup_path}\n"
@deploy.save
zip.mkdir(dup_path)
end
end
end
产生的结果是 运行正常 在代码中 调查 p @deploy 也是正常, 但是@deploy 并没有更新。
console中运行以下命令:
>> d = Deployment.last => #<Deployment id: 27, uuid: "decf4194a1b9640d126bf927ba259588d3c6811f", log: "sdfdfbaga", result: "", profile_id: 113403, pid: nil, status: "success", created_at: "2010-12-23 03:51:40", updated_at: "2010-12-23 04:05:22"> >> d.log << "hahaha" => "sdfdfbagahahaha" >> d.save => true >> d.log => "sdfdfbagahahaha" >> d.reload => #<Deployment id: 27, uuid: "decf4194a1b9640d126bf927ba259588d3c6811f", log: "sdfdfbaga", result: "public/f/tmp/level1.zip", profile_id: 113403, pid: nil, status: "success", created_at: "2010-12-23 03:51:40", updated_at: "2010-12-23 04:05:22"> >> d.log => "sdfdfbaga"
结果让人大吃一惊,原来 d.log << “xxxx” 在save前后并没有起到作用。
原因不明,按理说d.log << “xxx” 后 d.log #=> “xxx” 已经生效,d.save应该会把d的log更新了。
可惜事实不是如此。记录d只有在调用了log= 方法后 才会认为d被改变了。
以后在更新记录时切忌不要对单个字符串字段使用 << 或者concat 方法