Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

loop in templates

My template looks like:

  <h2>Oracle</h2>

  <% @q_oracle.each do |q| %>
    <%= link_to(q.title + ' (' + q.answer_count.to_s + ') ' + q.question_id.to_s, 'http://stackoverflow.com/' + q.question_answers_url) %>  </br>

  <% end %>


  <h2>Ruby and Rails</h2>

  <% @q_ruby.each do |q| %>
    <%= link_to(q.title + ' (' + q.answer_count.to_s + ') ' + q.question_id.to_s, 'http://stackoverflow.com/' + q.question_answers_url) %>  </br>

  <% end %>

So the temlate consists the static titles (h2) and loops through the array. I am searching the way to avoid copy-paste code in the my template. Something like:

@hash = { 'Oracle' => @q_oracle, 'Ruby and Rails' => @q_ruby }

@hash.each { |@t, @a|

  <h2>@t</h2>

  <% @a.each do |q| %>
    <%= link_to(q.title + ' (' + q.answer_count.to_s + ') ' + q.question_id.to_s, 'http://stackoverflow.com/' + q.question_answers_url) %>  </br>

  <% end %>
}

Is it possible?

like image 461
ceth Avatar asked Mar 31 '11 07:03

ceth


2 Answers

It's certainly possible, but it's putting an awful lot of Ruby logic in a view, which is kind of smelly. I think it would be better to factor out duplicated the question-list body portion into a partial.

Main view...

<h2>Oracle</h2>

<%= render :partial => 'question_list', :locals => {:questions => @q_oracle} %>


<h2>Ruby and Rails</h2>

<%= render :partial => 'question_list', :locals => {:questions => @q_ruby} %>

Partial: _question_list.html.erb ...

  <% questions.each do |q| %>
    <%= link_to(q.title + ' (' + q.answer_count.to_s + ') ' + q.question_id.to_s, 'http://stackoverflow.com/' + q.question_answers_url) %>  </br>

  <% end %>

This approach is more readable than the nested loop, and it's also more flexible in terms of customizing the page structure. For instance: what if you want to apply different styling to each list, or place a divider in between?

like image 159
Steve Jorgensen Avatar answered Nov 08 '22 12:11

Steve Jorgensen


Yes you can do it.

Ruby 1.9 solution

In Ruby 1.8 this solution can be used when titles order doesn't matter. In Ruby 1.9 titles would appear in order they were inserted in hash.

Just place this variable to your controller action:

@hash = { 'Oracle' => @q_oracle, 'Ruby and Rails' => @q_ruby }

And access this variable from your view:

<% @hash.each do |t, a| %>
  <h2><%= t %></h2>
  <% a.each do |q| %>
    <%= link_to(q.title + ' (' + q.answer_count.to_s + ') ' + q.question_id.to_s, 'http://stackoverflow.com/' + q.question_answers_url) %>  </br>
  <% end %>
<% end %>

Ruby 1.8 with sorted keys

This method sorts keys so they appear in alphabetical order.

<% @hash.keys.sort.each do |t| %>
  <h2><%= t %></h2>
  <% @hash[t].each do |q| %>
    <%= link_to(q.title + ' (' + q.answer_count.to_s + ') ' + q.question_id.to_s, 'http://stackoverflow.com/' + q.question_answers_url) %>  </br>
  <% end %>
<% end %>

Ruby 1.8 with arrays

This method would behave like Ruby 1.9 in any ruby version - titles would appear in order they were added.

Variable @hash must be initialized as:

@hash = [ ['Oracle', @q_oracle], ['Ruby and Rails',@q_ruby] ]

View must be updated to:

<% @hash.each do |title_with_questions| %>
  <h2><%= title_with_questions[0] %></h2>
  <% title_with_questions[1].each do |q| %>
    <%= link_to(q.title + ' (' + q.answer_count.to_s + ') ' + q.question_id.to_s, 'http://stackoverflow.com/' + q.question_answers_url) %>  </br>
  <% end %>
<% end %>
like image 40
Viacheslav Molokov Avatar answered Nov 08 '22 10:11

Viacheslav Molokov