【问题标题】:Rails Can't remove "\r\n" from recordRails 无法从记录中删除“\r\n”
【发布时间】:2026-02-02 06:55:01
【问题描述】:

我已经导入了一些数据 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

没有发布更新...

关于它为什么不起作用的任何想法?

【问题讨论】:

    标签: ruby-on-rails ruby csv activerecord rails-activerecord


    【解决方案1】:

    使用String.encode(universal_newline: true) 代替 gsub。 它将 CRLF 和 CR 转换为 LF

    【讨论】:

    • 这根本不能回答我的问题
    • 这也不会删除 '\n'
    【解决方案2】:

    您的问题是gsub! 就地修改了字符串:

    gsub!(pattern, replacement) → str or nil
    gsub!(pattern) {|match|块 } → str 或 nil
    gsub!(pattern) → an_enumerator

    在原地执行String#gsub 的替换,返回str,如果没有执行替换,则返回nil。 [...]

    gsub 很高兴有一个字符串作为它的第一个参数:

    gsub(模式,替换)→ new_str gsub(pattern, hash) → new_str
    gsub(pattern) {|match|块 } → new_str
    gsub(pattern) → 枚举器

    [...] 模式 通常是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", ' - ')
    

    那么您将用一个全新的字符串替换c.address,并且c.address_changed?c.changed? 都将为真。现在 ActiveRecord 将识别出您已更改 c 并且 c.save(或 c.save!)会将 UPDATE 发送到您的数据库中。

    请注意,gsub! 有时返回 nil 在这里完全无关紧要,您的代码中没有任何内容查看 gsub! 返回的内容,因此返回的内容无关紧要。


    我可能会在数据库中使用 SQL 直接执行此类操作,但具体操作方式取决于底层数据库。每当我想说Model.all 时,我都会感到畏缩,因为我习惯于处理大型数据库,而使用all 只是一种方便的记忆方式。

    【讨论】:

    • 这正是我想知道的。为什么 ActiveRecord 无法识别对象已更改。谢谢!
    • @Vargas:我认为了解问题的原因与修复它们同样重要。