Reputation: 6105
Sorry for this newbie question but I cannot figure how I can do this..
I have the following City table
# Table name: cities
#
# id :integer
# name :string(255)
# country :string(255)
(note: I am not using a separate Country table as I use Geokit-rails and think it is simpler to store all Google queries in the same table. However It would be easier to have separate tables to render what I want through a belong_to/has_many association)
In my city/index view I want to loop all the cities for each countries in order to render something like:
United States
New York
San Francisco
Los Angeles
United Kingdom
London
Spain
Madrid
...
By now, What I can get is what it provided by scaffolding
def index
@cities = City.all
end
<table>
<% for city in @cities %>
<tr>
<th><%= city.country %></th>
</tr>
<tr>
<td><%= city.name %></td>
</tr>
<% end %>
</table>
Rendering:
United States
Los Angeles
United States
New York
...
I didn't find any resource about this. I would be pleased if someone could help me (I don't know with which I have to start: find_by_ /params /each or collection?)
Thanks a lot!
Upvotes: 0
Views: 2674
Reputation: 1925
I've had success with the group_by
method:
@cities.group_by(&:country).each do |country, cities|
puts country.name
cities.each do |city|
puts "-> #{city.name}"
end
end
Output:
United States
-> New York
-> San Francisco
-> Los Angeles
United Kingdom
-> London
Spain
-> Madrid
-> Barcelona
Of course, you'll probably be doing this in an erb template, but the idea is the same:
<ul>
<% @cities.group_by(&:country).each do |country, cities| %>
<li><%= country.name %></li>
<li>
<ul>
<% cities.each do |city| %>
<li><%= city.name %></li>
<% end %>
</ul>
</li>
<% end %>
</ul>
Output:
Upvotes: 1
Reputation: 6516
The correct way to do this is to create a Country
table with id
and name
and in your City
model just keep a country_id
to the country, instead of a string
so
class Country < ActiveRecord::Base
has_many :cities
end
class City < ActiveRecord::Base
belongs_to :country
end
then you can call Country.includes(:cities)
and iterate over them like this in your view:
<% for country in countries %>
<%= country.name %>
<% for city in country.cities %>
<%= city.name %>
<% end %>
<% end %>
If you still want to use your way, you could do something like
@cities = City.order("country asc")
@countries = @cities.map(&:country).uniq!
<% for country in @countries %>
<%= country.name %>
<% for city in @cities %>
<%= city.name if city.country == country %>
<% end %>
<% end %>
Upvotes: 3