如何将字符串与 link_to 变量拼接在一起,这些变量的索引相对于 Ruby 中的字符串 Rails?

How can you splice together a string with link_to variables that have indices relative to the string in Ruby on Rails?

我正在尝试使用许多 post 示例文本 "you can find other #apple #orchard examples at www.google.com and www.bing.com #funfruit" 并使用 URL 和链接到其适当路线的#tags 向用户显示文本。

我已经成功地使用仅包含任意数量的#tags 或单个 URL 的文本完成了此操作,代码如下:

application_controller.rb

  def splice_posts(posts, ptags, spliced)
    # Build all posts as items in spliced, with each item an post_pieces array
    posts.reverse.each do |post| 
        tag_indices = [] 
        tag_links = [] 

        # Get post URLs: [{:url=>"www.google.com", :indices=>[209, 223]}]
        post_links = extract_urls_with_indices(post.text)
        # Save each as rails style link with indices


        # For each of the ptags associated with post 
        ptags.where(post_id:post.id).each do |ptag| 
            # Store hashtag's start/stop indices for splicing post 
            tag_indices.append([ptag.index_start, ptag.index_end]) 
            # Store hashtag links for splicing post
            tag_links.append(view_context.link_to '#' + ptag.hashtag, atag_path(Atag.find_by(id:ptag.atag_id).id), 
            :class => 'post_hashtag', :remote => true, :onclick => "location.href='#top'")
        end 

        # Create and store post as post_pieces in spliced
        # If there are no hashtags
        if tag_indices.length == 0 
            # And no links
            if post_links.length == 0
                spliced.append([post.text, post.id])
            # But links
            else
                spliced.append([post.text[0..post_links[0][:indices][0]-2], 
                view_context.link_to(post_links[0][:url], post_links[0][:url], target: "_blank"), 
                post.text[post_links[0][:indices][1]..-1], post.id])
            end


        # Elsif there is one hashtag
        elsif tag_indices.length == 1 
            if post.text[0] == '#' 
                spliced.append([post.text[2..tag_indices[0][0]], tag_links[0], 
                post.text[tag_indices[0][1]..-1], post.id]) 
            else 
                spliced.append([post.text[0..tag_indices[0][0]-2], tag_links[0], 
                post.text[tag_indices[0][1]..-1], post.id])
            end  

        # Else there are multiple hashtags, splice them in and store 
        else 
            # Reset counter for number of tags in this post
            @tag_count = 0 

            # If post begins with tag, no text before first tag
            if tag_indices[0][0] == 0 
                post_pieces = []
            # Else store text before first tag
            else 
                post_pieces = [post.text[0..tag_indices[0][0]-2]] 
            end 

            # Build core of post_pieces, splicing together tags and text
            tag_indices.each do |indice| 
                post_pieces.append(tag_links[@tag_count]) 
                post_pieces.append(post.text[indice[1]..tag_indices[@tag_count+1][0]-2]) 
                if @tag_count < (tag_indices.length-2) 
                    @tag_count += 1 
                else
                    # Do nothing
                end 
            end 

            # Knock off the junk at the end
            post_pieces.pop 
            post_pieces.pop 

            # Finish compiling post_pieces and store it in spliced
            post_pieces.append(tag_links[-1])
            post_pieces.append(post.text[tag_indices[-1][1]..-1])
            # Make last item in array post id for comment association purposes
            post_pieces.append(post.id)
            spliced.append(post_pieces)
        end                   
    end
  end

拼接后的 post 可以很容易地在视图中逐个显示:

<% @posts_spliced.each do |post_pieces| %>
     <%# Build post from pieces (text and hashtags), excluding last element which is post_id %>     
     <% post_pieces[0..-2].each do |piece| %>
        <%= piece %>
     <% end %>
<% end %>

问题是这个实现一开始就很复杂,试图用几十个嵌套的 if/else 语句来修补它来处理 URLs 似乎很疯狂,因为我怀疑更有经验的软件 engineer/rails 开发人员可以启发我如何使用一小部分代码来完成此操作。

为了澄清,我已经为每个 post(带有示例)提供了以下变量:

post = 'some text with #tags and www.urls.com potentially #multiple of each.com'

post_urls = [{:url=>"www.urls.com", :indices=>[25, 37]}, {:url=>"each.com", :indices=>[63, 71]}]

post_tags = [{:hashtag=>"tags", :indices=>[15, 20]}, {:hashtag=>"multiple", :indices=>[50, 59]}]

我认为更实际的实现可能更直接地涉及索引,但也许将 post 分解为数组中的元素完全是错误的想法,或者也许有更简单的方法,但是在我花几个小时概念化逻辑并为另一个可能的不理想解决方案编写代码之前,我想我应该看看是否有人可以在这里启发我。

非常感谢!

除非我遗漏了一些重要的东西,否则我认为你把事情复杂化了。

首先,你用空格分割字符串。

string = "whatever string typed in by user"
split_string = string.split

然后根据您的要求映射拆分字符串数组并加入结果。

# create show_hashtag(str) and show_link(str) helpers

split_string.map do |str|
  if str.starts_with?('#')
    show_hashtag(str)
  elsif url_regexp.match(str) # you must define url_regexp
    show_link(str)
  else
    str
  end
end.join(' ')

您不必担心文本、标签或链接的位置,因为 map 会为您处理。

将所有这些都包装在一个助手中,在您看来,您可以执行以下操作:

<%= your_helper(string_typed_in_by_user).html_safe %>

注意输入 HTML 的用户!