我想遍历系统中的所有用户,并使用电子邮件地址减去@和@之后的所有内容来更新用户名。 如果电子邮件是nil或空字符串,那么我只需为unknown_user分配当前的迭代索引:
User.all.each do |user|
puts user.email
username = (user.email.present?? user.email.gsub(/(.+)@.+/,$1) : "unknown_user#{i}")
puts username
end
失败了:
crodriguez
TypeError: no implicit conversion of nil into String
from (irb):45:in `gsub'
from (irb):45:in `block in irb_binding'
我不知道零值在哪里。如果没有电子邮件,则永远不会调用gsub。我在这里缺少什么?
答案 0 :(得分:4)
编号的全局变量($1
,$2
,...)仅在您使用String#gsub
的块形式时可用,因此您可以说:
user.email.gsub(/(.+)@.+/) { $1 }
当你说:
user.email.gsub(/(.+)@.+/, $1)
在构建$1
参数列表时(即在gsub
可以为其赋值之前)评估gsub
全局,因此您不应该期望{{1}有任何有用的价值。
那就是说,我可能会跟coreyward's approach一起去,而且根本不会打扰正则表达式。
答案 1 :(得分:3)
零值不是您的user.email
。 gsub
方法需要一个字符串作为它的第二个参数,它将替换匹配。正如mu分别指出的那样,当参数传递给$1
时,gsub
全局变量仍然不可用。
假设您只想要电子邮件的名称部分,您甚至不需要正则表达式:
username, _ = user.email&.split('@')
在此,username
nil
user.email
为nil
,@
之前为username
。
如果您确实要将User.find_each do |user|
username = user.email.split('@').first if user.email.present?
username ||= "unknown_user_#{user.id}"
# do something with `username`
end
设置为默认字符串,请参阅示例:
{{1}}
我已经在这里废除了三元,因为它不适合阅读或理解代码,并且在将来变得不那么容易。如果需要,你可以重构使用它。