Below is an application showing a list of tasks. The tasks are rendered in a table in one column. We could make better use of the space in the page by rendering them in multiple columns, but what’s the best way to do that? Rails provides a method called
in_groups_of as an extension to the
Array object that helps us to do this.
Our task list in a single column.
To demonstrate how in_groups_of works we’ll show it in action in the console.
>> a = (1..12).to_a => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] >> a.in_groups_of(4) => [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] >> a.in_groups_of(3) => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
In the first row above we create an array with twelve elements from a range. The
in_groups_of method can be used with a single argument to return an array of arrays, each containing n elements, where n is the value of the argument passed. In the code above we split the array first into three groups of four and then into four groups of three. (Note that
in_groups_of returns a copy of the array and doesn’t alter the original.)
Displaying Our Tasks In Columns
Now that we know how to use
in_groups_of we can use it in our view code to display our task list in columns. The relevant part of our index view currently looks like this.
<table> <% @tasks.each do |task| %> <tr> <td><%= task.name %></td> </tr> <% end %> </table>
We’ll change it to look like this.
<table> <% @tasks.in_groups_of(4) do |tasks| %> <tr> <% tasks.each do |task| %> <td><%= task.name %></td> <% end %> </tr> <% end %> </table>
We can use a block with
in_groups_of, so we’ll split our tasks into groups of four, output an opening
tr tag, then loop through each task in that group and output it between
td tags. The result is shown below.
Our tasks are now rendered in four columns as we wanted, but we’re not quite there yet. As we’re rendering twelve tasks in groups of four, we have three full rows of tasks. If we add a couple more and refresh the page the following happens.
We can see the reason for this if we go back to the console and try to split our array of twelve numbers into groups of five.
>> a = (1..12).to_a >> a.in_groups_of(5) => [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, nil, nil, nil]]
If there aren’t enough elements to fill the last array,
in_groups_of will pad it with
nils. To stop this, we can pass a second argument. If the second argument is
false then the last array will be shorter than the others; if we pass any other value then the last array is padded out with that value.
>> a.in_groups_of(5, false) => [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12]] >> a.in_groups_of(5, 0) => [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 0, 0, 0]] >>
If we use
false as the second argument to our
in_groups_of in the view code then the page will render no matter what the number of tasks we have.