查找某个特定字符的所有实例并替换字符&跟随超链接的单词

时间:2014-08-12 20:19:41

标签: ruby-on-rails ruby replace gsub

我正在开发一个Twitter副本项目,用于我正在尝试使用指向相应用户名的个人资料页面的超链接,在推文中超链接任何@username实例。使用gsub我可以让替换工作,但如果推文有多个不同的@usernames实例,它只用第一个用户名替换它们。这就是我到目前为止所拥有的:

  def twet_link_replacer(twet)
    if twet.content.include? "@" 
      username = twet.content.match(/@(\w+)/)
      content_tag :p, twet.content.gsub!(/@(\w+)/, link_to(username, '/twets/'+username.to_s.gsub(/@/,""))).html_safe  
    else 
      content_tag :p, twet.content 
    end 
  end

谢谢!

2 个答案:

答案 0 :(得分:2)

你在这里做了太多的工作。当您使用twet.content.include? "@"时,我没有理由致电gsub,因为如果找不到gsub@将无法执行任何操作。出于同样的原因,您也不需要if...else。这样的东西就足够了:

def twet_link_replacer(twet)
  new_content = twet.content.gsub(/@(\w+)/) do |username|
    link_to(username, "/twets/#{$1}")
  end

  content_tag :p, new_content
end

这使用gsub的块参数,让我们将匹配替换为link_to的结果。在阻止内部,username是完整匹配的文字(例如"@Jordan"),$1是第一个(也是唯一的)捕获组(例如"Jordan")。

您的代码还有其他一些问题。首先,在用户输入上使用html_safe。我假设twet.content来自用户输入,因此本质上是不安全的。通过信任它(这是html_safe所暗示的 - 它告诉Rails,"不要逃避这个字符串,因为我相信它是安全的")你让你的应用程序对XSS攻击敞开大门

其次,当您使用字符串连接或插值(例如"/twets/" + username"/twets/#{username}")来创建要提供给link_to的网址或路径时,您需要可能犯了一个错误。这取决于您的路线是什么样的,但是如果您正在使用resourceful routes,那么您应该使用,例如。

# instead of this...
link_to(username, "/users/" + username)

# you can just do this...
link_to(username, user_path(username))

...会自动为您生成一个网址,如果您稍后更改路线,则无法更改您的观看次数或帮助,因为user_path会随路径自动更改。

同样,这取决于您如何定义路线,但这是您应该尝试的方向。

答案 1 :(得分:1)

问题是您使用两个不同的正则表达式来匹配用户名。将它们结合起来得到你想要的东西。

def twet_link_replacer(twet)
  if twet.content.include? "@"
    content_tag :p, twet.content.gsub!(/@(\w+)/, link_to('\1', '/twets/\1')).html_safe
  else
    content_tag :p, twet.content
  end
end