2016-12-30 81 views
0

我想循环遍历系统中的所有用户,并使用电子邮件地址减去@和@之后的所有内容更新用户名。 如果电子邮件是零或空字符串,然后我就分配unknown_user与当前迭代指数:TypeError:没有隐式将nil转换为带有gsub的字符串

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

请注意,这实际上并没有更新任何它只是简单地分配一个局部变量。如果你已经知道,我很抱歉。此外,它不会出现你正在验证的电子邮件地址为“crodriguez”不是一个有效的电子邮件 – engineersmnky

+2

FYI:要在gsub替换模式中使用反向引用,只需使用''\ 1'':'gsub(/(.+) @。+ /,'\ 1')' –

回答

3

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

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

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

在此,usernameniluser.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 

我免掉这里的三元,因为它不是适合于阅读和理解的代码,未来改变并不容易。如果需要,您可以重构使用它。

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

当你说:

+2

更紧凑的选项:'username = user.email.to_s.split('@')。 “unknown_user _#{user.id}”' – Thilo

+0

@Thilo当'user.email'为零时,你会得到一个NoMethodError。 ;) – coreyward

+1

@coreyward'nil.to_s#=>“”':)。现在真正的问题是,他没有看到他正在验证电子邮件地址,它可能根本不包含@。 – engineersmnky

4

编号的全局变量($1$2,...)当您使用的String#gsub块形式,所以你可以说是唯一可用的

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

$1全局评估当gsub参数列表正在构建(即在gsub可以分配它的值之前),所以你不应该期望$1有什么有用的价值。

这就是说,我可能会去coreyward's approach,而不是打扰一个正则表达式。

+0

+1我没有意识到全球任务的幕后。你总是领先我一步。 – coreyward

+1

@coreyward编号的全局变量是从Perl中复制出来的一个疣,它们闻到霉味,并且是一种错误的IMO。 –

+0

我比其他人更早学习了Ruby,所以到了那时,他们已经被折服了。我从来没有真正在拷贝粘贴代码之外使用它们。不过,我认为这里更有趣的部分是解释和执行过程中发生的事情。 – coreyward

相关问题