I have csv import table model:
class ImportTable < ActiveRecord::Base
has_many :import_cells, :dependent => :destroy
end
class ImportCell < ActiveRecord::Base
belongs_to :import_table
end
The controller is (edited for brevity):
def show
@import_table = ImportTable.find(params[:id])
@import_cells = @import_table.import_cells
@row_index_max = @import_cells.map { |cell| cell.row_index }.max
@column_index_max = @import_cells.map { |cell| cell.column_index }.max
end
The import_cells have a row_index
and column_index
, I group them by columns in the view.
<table border="1" cellspacing="1" cellpadding="1">
<tr>
<% 0.upto(@column_index_max) do |column_index| %>
<th>
<%= f.select(column_index, []) %>
</t开发者_StackOverflow中文版h>
<% end %>
</tr>
<% 0.upto(@row_index_max) do |row_index| %>
<% row = @import_cells.select { |cell| cell.row_index == row_index } %>
<tr>
<% 0.upto(@column_index_max) do |column_index| %>
<td>
<%= row.select { |cell| cell.column_index == column_index }[0].contents %>
</td>
<% end %>
</tr>
<% end %>
</table>
I cribbed this from another website and it seems sort of janky to me. Simply adding:
@import_cells = @import_table.import_cells.paginate(:all, :order => "row_index ASC", :per_page => @column_index_max * 16, :page => params[:page])
Doesn't quite work as there will be nil objects created by will_paginate
that have to be dealt with. It seems to me there is too much logic in the view. What's a good approach to take here? I'm thinking of adding a row
method to group the columns in the ImportTable
model itself but it would have to be flexible depending on how many columns are in a particular table. Then the rows could be paginated.
Any thoughts, suggestions, and nudges in the "rails way" direction appreciated!
We have a setup similar to this in the site I'm working on, and I dealt with it as follows:
Build a "table" (actually an array of arrays) in the controller:
@table = []
max_col = 0
@table_cells.each do |cel|
@table[cel.row] ||= []
@table[cel.row][cel.col] = cel
max_col = [max_col, cel.col].max
end
#This bit fleshes out your rows with nils to ensure you have a rectangular table:
# (edited to handle empty rows properly)
@table.each_with_index do |row, i|
@table[i] = [] unless row
@table[i][max_col] ||= nil
end
And in the view, all you have to do is loop through the table and show the cels:
<table>
<% @table.each do |row| -%>
<tr>
<% row.each do |cel| -%>
<td><%=h cel.whatever %></td>
<% end -%>
</tr>
<% end -%>
</table>
The downside of this method is that you have to build the whole table in memory before rendering the page (you could probably do it a row at a time if you sorted your columns properly). The upsides are that it sticks to MVC (and thus the "Rails Way") pretty nicely, and @table
is widely useful once you have a function to build it - once you have it, you can output just about any format you want just by tweaking the view. We use it for HTML and CSV, and plan to add XLS as soon as someone has time to learn the format.
精彩评论