TypeError:没有使用gsub将nil隐式转换为String

时间:2016-12-30 18:30:07

标签: ruby-on-rails ruby regex

我想遍历系统中的所有用户,并使用电子邮件地址减去@和@之后的所有内容来更新用户名。 如果电子邮件是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。我在这里缺少什么?

2 个答案:

答案 0 :(得分:4)

编号的全局变量($1$2,...)仅在您使用String#gsub的块形式时可用,因此您可以说:

user.email.gsub(/(.+)@.+/) { $1 }

当你说:

user.email.gsub(/(.+)@.+/, $1)

在构建$1参数列表时(即在gsub可以为其赋值之前)评估gsub全局,因此您不应该期望{{1}有任何有用的价值。

那就是说,我可能会跟coreyward's approach一起去,而且根本不会打扰正则表达式。

答案 1 :(得分:3)

零值不是您的user.emailgsub方法需要一个字符串作为它的第二个参数,它将替换匹配。正如mu分别指出的那样,当参数传递给$1时,gsub全局变量仍然不可用。

假设您只想要电子邮件的名称部分,您甚至不需要正则表达式:

username, _ = user.email&.split('@')

在此,username nil user.emailnil@之前为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}}

我已经在这里废除了三元,因为它不适合阅读或理解代码,并且在将来变得不那么容易。如果需要,你可以重构使用它。