开发者

Grouping data and pagination with Rails

开发者 https://www.devze.com 2023-02-08 09:20 出处:网络
I have csv import table model: class ImportTable < ActiveRecord::Base has_many :import_cells, :dependent => :destroy

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消