我们有一个旧的MySQL数据库字段,其中包含以下格式的电话号码:
(xxx) xxx-xxxx
我想将它们更改为数字(xxxxxxxxxx
)。我找到了以下link的解决方案,但我想写一个rake文件来执行此操作。
UPDATE table_name set PhoneCol = REPLACE(PhoneCol, '(', '');
UPDATE table_name set PhoneCol = REPLACE(PhoneCol, ') ', '-');
如何在 Active Record 上运行这些命令?我已经把它解决了
Model.update_all(phone: ???)
答案 0 :(得分: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, ') ', '-')")
如果您期望撤消更改,则可以创建两个rake任务:
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
我建议将其放在具有up
和down
方法的迁移文件中,但这不是更新此类数据的好方法,即迁移文件应始终处理架构更改,而不是数据库中的数据更新。因为,当您的项目增长时创建新的迁移时,您将没有任何其他选择在不参考其版本号的情况下在该迁移上运行回滚,并且如果您(或其他人)错过了,您可能会面临任何机会生产服务器上的严重数据丢失。这就是为什么你的更新脚本应该在rake任务中(这不包括保证你的数据更新是可逆的)。
答案 1 :(得分:0)
我认为您应该以正确的格式存储电话号码,即ITU E.164 Format。有一个名为Google’s libphonenumber的global_phone的Ruby端口,用于解析人们提出的各种疯狂输入。您可以使用以下代码段清理特定数据库列中的所有数字:
Model.find_each do |model|
normalized_number = GlobalPhone.normalize(model.phone_number)
model.update_attribute('phone_number', normalized_number)
end
我还建议使用before_validation
回调,或者,如果您需要许多列,可以使用attribute_normalizer这样的Gem,它可以帮助您在用户输入新数字时清理新记录。然后,您可以定义自己的规范化器,使用global_phone Gem来规范化电话号码。
最后,以适合用户的格式显示数字是视图层的责任,您可以在其中获取全局明确的E.164格式的数字并根据需要重新格式化,就像使用{例如,{1}}列。如果您希望获得真正的想象力,您还可以覆盖所涉及属性的getter,以便调用Date
直接返回已解析的model.phone_number
对象而不是字符串;通过这种方式,您可以保持视图清除对GlobalPhone::Number
的调用。