2014-11-05 69 views
0

我们必须在以下格式的电话号码一个旧版本的MySQL数据库字段:的ActiveRecord格式的电话号码

(xxx) xxx-xxxx 

我想改变他们只是数字(xxxxxxxxxx)。我在下面的link上找到了解决方案,但是我想编写一个rake文件来执行此操作。

UPDATE table_name set PhoneCol = REPLACE(PhoneCol, '(', ''); 
UPDATE table_name set PhoneCol = REPLACE(PhoneCol, ') ', '-'); 

如何运行活动记录这些命令?我已经工作了,以

Model.update_all(phone: ???) 
+0

请看这里:https://stackoverflow.com/questions/4483049/how-to-execute-a-raw-update-sql-with-dynamic-binding-in-rails – mcfinnigan 2014-11-05 11:58:48

+0

为什么你需要Rakefile?你可以使用Rails控制台做到这一点..对吗? – 2014-11-05 11:59:44

+0

@ User089247如果这是需要,为什么不修复它来自哪里的实际来源。为什么双重工作? – 2014-11-05 12:05:42

回答

0

运行原始的SQL查询:

ActiveRecord::Base.connection.execute("UPDATE table_name set PhoneCol = REPLACE(PhoneCol, '(', '');") 
ActiveRecord::Base.connection.execute("UPDATE table_name set PhoneCol = REPLACE(PhoneCol, ') ', '-');") 

或你自己说的,使用update_all

Model.update_all("'PhoneCol' = REPLACE(PhoneCol, '(', '')") 
Model.update_all("'PhoneCol' = REPLACE(PhoneCol, ') ', '-')") 

如果你期待撤消更改,那么你可以创建两个耙任务:

namespace :phone_column do 
    desc "Update phone column from (xxx) -xxxx to xxx-xxxx" 
    task :update => :environment do 
    Model.update_all("'PhoneCol' = REPLACE(PhoneCol, '(', '')") 
    Model.update_all("'PhoneCol' = REPLACE(PhoneCol, ') ', '-')") 
    end 

    # NOTE: running this task can mess up the data if you have not run the previous task before 
    desc "Reverse xxx-xxxx to (xxx) -xxxx" 
    task :reverse => :environment do 
    Model.update_all("'PhoneCol' = CONCAT('(', SUBSTRING_INDEX(PhoneCol, '-', 1), ') ', SUBSTRING_INDEX(PhoneCol, '-', 2), '-', SUBSTRING_INDEX(PhoneCol, '-', -1))") 
    end 
end 

我会建议把这个与updown方法迁移文件,但是这没有更新这样的数据的一个很好的方式,即迁移文件应该总是处理模式的变化,而不是在你的数据库中的数据更新。因为,随着项目的增长,当您创建新的迁移时,您将不会有任何其他选择在不参考其版本号的情况下对该迁移进行回滚,并且如果您(或其他人)错过了任何机会,您可能会面临生产服务器上严重的数据丢失。这就是为什么你的更新脚本应该在rake任务中(这不包括保证你的数据更新是可逆的)。

+0

运作良好。但我如何撤消更改? – 2014-11-05 12:11:23

+0

@MarcoLau:查看最新版本 – Surya 2014-11-05 12:49:58

0

我觉得你应该存储电话号码以正确的格式,这是ITU E.164 Format。有一个名为global_phoneGoogle’s libphonenumber红宝石端口,它解析了各种疯狂的输入人物。您可以消毒在特定数据库列的所有数字与下面的代码片段:

Model.find_each do |model| 
    normalized_number = GlobalPhone.normalize(model.phone_number) 
    model.update_attribute('phone_number', normalized_number) 
end 

我还建议使用before_validation回调,或者,如果你需要它的许多列,这样的创业板attribute_normalizer这将帮助你清理新记录为用户输入新号码。然后你可以定义你自己的标准化程序,它使用global_phone Gem来标准化电话号码。

最后,以适合用户的格式显示数字是视图层的责任,您可以在其中采用全局明确的E.164格式的数字并按照您的喜好重新格式化它们,就像您使用例如,Date列。如果你想获得真正看中的,你也可以覆盖干将对所涉及的属性,因此,调用model.phone_number直接返回一个解析GlobalPhone::Number对象,而不是一个字符串;通过这种方式,您可以保持对GlobalPhone.parse调用的清晰度。