我已导入一些数据com CSV文件,最后在列中包含一些包含字符串“\ r \ n”的记录。再次导出为CSV时,这些行会在插入新行时将这些行搞砸...
我试图删除一个Rake任务,但似乎ActiveRecord没有发出UPDATE查询,我无法弄清楚我做错了什么...
这就是我正在做的事情:
Contact.all.each {|c|
next if c.address.nil? || !c.address.include?("\r\n");
c.address.gsub!("\r\n", " - ");
c.save;
}
这是rails c -s
会话的输出:
(1.7ms) SAVEPOINT active_record_1
(0.1ms) RELEASE SAVEPOINT active_record_1
(0.0ms) SAVEPOINT active_record_1
(0.0ms) RELEASE SAVEPOINT active_record_1
(0.1ms) SAVEPOINT active_record_1
(0.1ms) RELEASE SAVEPOINT active_record_1
(0.0ms) SAVEPOINT active_record_1
(0.0ms) RELEASE SAVEPOINT active_record_1
没有UPDATE发布......
为什么它不起作用的任何想法?
你的问题是gsub!
就地修改了字符串:
gsub!(模式,替换)→str或nil gsub!(模式){|匹配| block}→str或nil gsub!(模式)→an_enumerator
如果没有执行替换,则执行
String#gsub
的替换,返回str或nil
。 [...]
gsub
很高兴有一个String作为它的第一个参数:
gsub(模式,替换)→new_str gsub(模式,哈希)→new_str gsub(pattern){| match | block}→new_str gsub(模式)→枚举器
[...]模式通常是
Regexp
;如果作为String
给出,它包含的任何正则表达式元字符将按字面解释[...]
所以s.gsub!("\r\n", ' - ')
和s.gsub!(/\r\n/, ' - ')
将具有完全相同的效果。
那么当你使用gsub!
时会发生什么?如果你这样做:
c.address.gsub!("\r\n", " - ")
你以ActiveRecord无法识别的方式更改c.address
。例如,在Rails控制台中尝试:
> c = Address.find(some_valid_id)
> c.address.gsub!('e', 'x') # Assuming that the address has an 'e' in it of course...
> c.changed?
=> false
> c.address_changed?
=> false
所以你已经改变了地址字符串,但ActiveRecord不会知道,因为c.address
仍然是同一个String对象。由于ActiveRecord认为没有任何改变,c.save
将不会做任何事情。
如果你切换到gsub
版本:
c.address = c.address.gsub("\r\n", ' - ')
那么你将用一个全新的String替换c.address
,而c.address_changed?
和c.changed?
都将成为现实。现在,ActiveRecord将识别您已更改c
并且c.save
(或c.save!
)将向您的数据库发送UPDATE。
请注意,gsub!
有时返回nil
在这里完全无关紧要,你的代码中没有任何内容可以查看gsub!
返回的内容,因此返回它并不重要。
我可能会在SQL数据库内部做这类事情,但是你如何做的具体细节取决于底层数据库。每当我想说Model.all
时,我都会畏缩,因为我习惯于处理大型数据库,使用all
只是一种方便的方式来挫败你的记忆。
使用String.encode(universal_newline: true)
而不是gsub。它将CRLF和CR转换为LF