blahedo
blahedo

Reputation: 834

Can I make an array of links using link_to in Rails?

I have a list of values in url/title pairs that I'd like to display. (More specifically, each object has its own list of links, some with 0, some with 1, some with more.) I would like them to appear in a list that is comma-separated. So I wrote this in my .erb file:

<%= links.map{|wl| link_to wl.title, wl.url}.join(', ') %>

Somewhat to my surprise, this displayed a comma-separated list of the HTML code for the links I wanted to create; that is, it was taking all the angle brackets and ampersand-encoding them. Just to make sure there wasn't anything funny in the higher-order functions, I tried a more imperative version:

<% a = [] %>
<% links.each do |wl| %>
  <% a << link_to(wl.title, wl.url) %>
<% end %>
<%= a.join(', ') %>

with, of course, the same result. But I don't think I'm misusing link_to, because if I modify that to

<% links.each do |wl| %>
  <%= link_to(wl.title, wl.url) %>,
<% end %>

then it actually creates links. It's almost exactly what I want, except that there's an extra comma after the last one. Is there some magic going on under the hood with link_to that makes it act differently depending on where its output is heading? Is there any way to bypass that magic? The join semantics would be exactly what I want here, and I can obviously figure out how to roll my own (using each_index, I guess) but it seems like an awfully heavy and un-Ruby solution to what must be a common problem.

Upvotes: 13

Views: 6703

Answers (6)

Viktor Ivliiev
Viktor Ivliiev

Reputation: 1334

you can use RAW:

= raw inks.map{|wl| link_to wl.title, wl.url}.join(', ')

Or

= render partial: 'links/link', collection: links, spacer_template: 'shared/comma' 

as suggested by Alex Peachey

Upvotes: 0

Gerry Shaw
Gerry Shaw

Reputation: 9378

Use safe_join combined with html_safe on the separator string.

Example:

<%= safe_join(links.map { |l| link_to(l.title, l.url) }, ", ".html_safe) %>

Upvotes: 20

smoyth
smoyth

Reputation: 709

Try putting this in your ApplicationHelper

  def sep(separator)
    ->(a, b){ a << separator.html_safe << b }
  end

Then do this in your template

links.map{|wl| link_to wl.title, wl.url}.reduce(&sep(", "))

You can use any separator you like this way. You also don't need to call html_safe on the whole thing either. Only the separator. So this method is more secure.

Upvotes: 2

Alex Peachey
Alex Peachey

Reputation: 4686

While the suggestions to use html_safe will get the result you are going for, I would suggest you not stick loops like that in your view. There is a perfectly good way in rails to do what you are looking for:

In your main view file where you currently have your loop change it to this:

<%= render partial: 'links/link', collection: links, spacer_template: 'shared/comma' %>

Then create a partial links/_link.html.erb

<%= link_to link.title, link.url %>

Then create a partial shared/_comma.html.erb

,

The nice thing about this approach is you don't have to worry if your link content is actually safe and if you choose to list or style it another way it's as simple as changing one or both of the templates. For example if instead of commas you decide you want it vertical and use <br> instead of , in your spacer template.

Upvotes: 6

James Lim
James Lim

Reputation: 13054

Try

<%= links.map{|wl| link_to wl.title, wl.url}.join(', ').html_safe %>

This instructs Rails to not escape the text.

Upvotes: 12

Puhlze
Puhlze

Reputation: 2614

Rails will convert strings to be html safe by default. Your join call turns the links output into a string, which is why the text is then being escaped. Try adding .html_safe after the join call, which will tell rails that the text you are providing is html safe and so does not need to be escaped. There's more on how this works at: http://yehudakatz.com/2010/02/01/safebuffers-and-rails-3-0/

Upvotes: 1

Related Questions