SuperString
SuperString

Reputation: 22519

Rails: link_to method

I have something like this:

<p>
  <b>Tags:</b>
  <%if @post.tags.count > 0%>
    <%= @post.tags.collect {|c| (link_to c.name, c)}.join(", ")%>
  <%else%>
    Does not have any tags.
  <%end%>
</p>

Which gives me

Tags: <a href="/tags/1">Java</a>, <a href="/tags/2">CSS</a>

Instead of Java and CSS links. What am I missing?

Upvotes: 1

Views: 3305

Answers (3)

PeterWong
PeterWong

Reputation: 16011

I think your tag names should be input by the user, right?

In this case, html_safe is not your first choice, as it gave full trust to the user. And your site would encounter XSS attacks.

The better choice should be sanitize. See the reference here: http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html

As you only want to have links, the following line do what you want:

<%= sanitize @post.tags.collect {|c| (link_to strip_links(c.name), c)}.join(", "), :tags => %w(a) %>

Note the use of strip_links(c.name), this removes all the links that input by the user.

Let's assume the tag names are: ["Product", "hi", "bye"]

By just using .html_safe, the following would be shown:

<a href="/tags/1">Product</a>, <a href="/tags/2"><strong>hi</strong></a>, <a href="/tags/3"><a href='bad_site.com'>bye</a></a>

But using the mix of sanitize with strip_links, the following is the result:

<a href="/tags/1">Product</a>, <a href="/tags/2">&lt;strong&gt;hi&lt;/strong&gt;</a>, <a href="/tags/3">bye</a>

Or you could mix the use of strip_tags with .html_safe:

<%= @post.tags.collect {|c| (link_to strip_tags(c.name), c)}.join(", ").html_safe %>

This simply removes all tags in c.name before you call the html_safe.

I would suggest (and you probably are doing already :D) removing all unwanted tags before storing into the database.

Upvotes: 1

Brian Donovan
Brian Donovan

Reputation: 8400

It's because strings in Rails 3 are, by default, not considered HTML-safe. See this blog post about it.

You can manually mark something as safe by calling .html_safe on it, which would make your code like so:

<p>
  <b>Tags:</b>
  <%if @post.tags.count > 0%>
    <%= @post.tags.collect {|c| (link_to c.name, c)}.join(", ").html_safe %>
  <%else%>
    Does not have any tags.
  <%end%>
</p>

But I'd recommend doing this instead:

<p>
  <b>Tags:</b>
  <% if @post.tags.count > 0%>
    <% @post.tags.each_with_index do |tag, i| %>
      <%= link_to h(tag.name), tag %><%= ', ' if i < @post.tags.size - 1 %>
    <% end %>
  <% else %>
    Does not have any tags.
  <%end%>
</p>

Upvotes: 6

jonepatr
jonepatr

Reputation: 7809

I think html_safe is what you are looking for! So this would solve the problem (@post.tags.collect {|c| (link_to c.name, c)}.join(", ")).html_safe

Upvotes: 3

Related Questions