0

I have a problem.

I have a Video and Comment model. If the user inserted the link to video into the comment, it is link to replace with the title from video.

How should I write a method?

def to_show_title_instead_of_the_link
  body.gsub!(%r{(videos)\/([0-9])}) {|link| link_to link)}
end

We input:

http://localhost:3000/videos/1

We receive:

<a href="http://localhost:3000/videos/1"> test video</a>
vadus1
  • 99
  • 9

2 Answers2

2

It sounds like you want to take a given URL on your site, and find the associated parameters for that route. This will let you get the id for the video in a clean, DRY way (without using a regex that might break later if your route changes). This will then let you look up the model instance and fetch its title field. The Rails method for this task is Rails.application.routes.recognize_path, which returns a hash with the action, controller, and path parameters.

In your view:

# app\views\comments\show.html.erb
# ...
<div class='comment-text'>
  replace_video_url_with_anchor_tag_and_title(comment.text)
</div>
# ...

And here is the helper method:

# app\helpers\comments_helper.rb
def replace_video_url_with_anchor_tag_and_title(comment_text)
  # assuming links will end with a period, comma, exclamation point, or white space
  # this will match all links on your site
  # the part in parentheses are relative paths on your site
  # \w matches alphanumeric characters and underscores. we also need forward slashes
  regex = %r{http://your-cool-site.com(/[\w/]+)[\.,!\s]?}
  comment_text.gsub(regex) do |matched|
    # $1 gives us the portion of the regex captured by the parentheses
    params = Rails.application.routes.recognize_path $1

    # if the link we found was a video link, replaced matched string with
    # an anchor tag to the video, with the video title as the link text
    if params[:controller] == 'video' && params[:action] == 'show' 
       video = Video.find params[:id]
       link_to video.title, video_path(video)

    # otherwise just return the string without any modifications
    else
       matched
    end
  end
end

I didn't know how to do this off the top of my head, but this is how I figured it out:

1) Google rails reverse route, and the first result was this stackoverflow question: Reverse rails routing: find the the action name from the URL. The answer mentions ActionController::Routing::Routes.recognize_path. I fired up rails console and tried this out, however it is deprecated, and didn't actually work.

2) I then google rails recognize_path. The first search result was the docs, which were not very helpful. The third search result was How do you use ActionDispatch::Routing::RouteSet recognize_path?, whose second solution actually worked.

3) Of course, I then had to go refresh my understanding of Ruby regex syntax and gsub!, and test out the regex I wrote above =)

Community
  • 1
  • 1
Daniel Waltrip
  • 2,530
  • 4
  • 25
  • 30
  • No problem! I was actually just thinking about this a little more, and it isn't the cleanest way to just run this method on the entire `body` text. We should use it as a helper method for comment views, and run the regex just for the text of the comment. I updated my answer to show you what I mean. – Daniel Waltrip Feb 08 '14 at 00:12
  • 1
    I understand, thanks again. I will process your method and I will write his version. – vadus1 Feb 08 '14 at 00:18
1

I did refactoring code and used a gem rinku

def links_in_body(text)
  auto_link(text) do |url|
    video_id = url.match(/\Ahttps?:\/\/#{request.host_with_port}\/videos\/(\d+)\z/)
    if video_id.present?
      Video.find(video_id[1]).title
    else
      truncate(url, length: AppConfig.truncate.length)
    end
  end
end
vadus1
  • 99
  • 9