如何在Rails中自动链接到文本提交中的对象

Joh*_*tta 5 ruby search ruby-on-rails

所以,你在Github提交了一个问题,你提到的问题是#31.然后,在写这个问题时,你注意到@johnmetta已经提出了他正在研究的一些可能的解决方案.然后你点击"提交新问题",当你这样做时,"#31"和"@johnmetta"是链接,并且@johnmetta已被通知,问题#31有一个通知它已被引用.

我意识到这里有不止一种技术(Javascript好东西等),但我正在寻找的是如何在Rails世界中做这类事情的一些例子.这是一个有趣的搜索难题.

我从概念上提出的是:

  1. 有一些标识符,例如保留的#或@
  2. 提交后,在适当的属性中搜索该标识符
  3. 找到它后,使用与后面匹配的字段搜索相应的模型
  4. 找到后,用链接替换该文本字符串
  5. (可选)执行必要的操作以通知引用的对象

也就是说,它似乎非常简单(明确编码,假设为friendly_id).

def prettify_user_links(str, source):
  result = str
  str.scan(/(@\S+)+/).each do |mtch|
    # Strip off whatever identifier we're using
    search_string = mtch[0].gsub('@','')
    # Search for the matching model in the appropriate table
    user = User.find(search_string)
    if user
      # If we find a matching model, create some link text and link it
      link_txt = "<a href=>'#{user.url}'>#{mtch}</a>"
      result.gsub!(search_string, link_txt)
      # Notification. Not sure how/where, maybe with a message bus, or something more brute-force like
      Comment.create :user_id => user.id, :body => "You have been mentioned in #{link_to comment.excerpt, comment} by #{link_to comment.owner, owner}"
  return result
Run Code Online (Sandbox Code Playgroud)

这将是我的第一次削减,但我觉得必须有更优雅的解决方案.

这个问题的另一个方面是:你如何抓住周围文本的snippit.蛮力方式是搜索之前的n个单词并在该字符串之后搜索m个单词并抓取所有这些,然后从结果中获取该子字符串并进行搜索.似乎还有一个更优雅的解决方案.

Cyb*_*fox 2

你所描述的是基本方法;没有什么比这更优雅的了。将其视为两部分会很有帮助:一部分是在收到评论时(当您应该执行通知时),另一部分是在显示评论时,当您应该执行链接时。

这使您可以保留原始评论的原始形式,这很有帮助。

也许在评论模型上放置一个 after_create (因此不会在每次编辑时发送通知)(假设评论模型包含“正文”字段):

[编辑:添加上下文信息]

after_create :notify_mentions

def notify_mentions
  body.scan %r{(.{0,40})@(\w+)(.{0,20})} do |match|
    username = match[1]
    context = [match.first, match.last]
    Notification.send(match, context, self) if User.exists?(:login => username)
  end
end
Run Code Online (Sandbox Code Playgroud)

我用\w+“of”来代替,\S+因为人们经常说这样的话:

嘿@JohnMetta,你好吗?

并将\S+捕获,可能错误的内容。将其@从捕获组中拉出可以让我在通知期间忽略它。

context上面的匹配组由您的代码段的匹配用户名之前的 40 个字符和之后的 20 个字符组成。调整口味。

然后,当显示消息时,您实际上创建了一个类似于您所拥有的助手:

def linkify(body)
  body.gsub %r{@\w+} do |match|
    link_to match, :controller => :users, :action => :show, :id => match
  end
end
Run Code Online (Sandbox Code Playgroud)

#gsub非常棒,因为它需要一个块并替换为内容。

它并不比你所拥有的优雅多少,但它应该给出一个相当不错的结果。