table-for 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -1
- data/Gemfile.lock +13 -3
- data/README.rdoc +137 -184
- data/VERSION +1 -1
- data/app/views/table_for/_table_for.html.erb +42 -39
- data/example.rdoc +138 -0
- data/example_table.png +0 -0
- data/lib/table_for.rb +10 -0
- data/lib/table_for/base.rb +3 -9
- data/lib/table_for/helper_methods.rb +88 -0
- data/lib/table_for/view_additions.rb +1 -53
- data/spec/integration/table_for_spec.rb +455 -455
- data/spec/spec_helper.rb +1 -0
- data/spec/table_for/helper_methods_spec.rb +96 -0
- data/spec/table_for/view_additions_spec.rb +0 -86
- data/table-for.gemspec +12 -5
- metadata +25 -5
data/Gemfile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
3
|
gem 'rails', ">= 3.0.0"
|
4
|
-
gem 'blocks', "~> 2.
|
4
|
+
gem 'blocks', "~> 2.3.0"
|
5
5
|
|
6
6
|
group :development do
|
7
7
|
gem "rspec-rails", ">= 2.0.0.beta.20"
|
@@ -12,4 +12,5 @@ group :development do
|
|
12
12
|
gem "with_model", '0.2.6'
|
13
13
|
gem "bundler", "~> 1.3.5"
|
14
14
|
gem "jeweler", "~> 1.8.4"
|
15
|
+
gem "debugger"
|
15
16
|
end
|
data/Gemfile.lock
CHANGED
@@ -29,10 +29,19 @@ GEM
|
|
29
29
|
i18n (= 0.6.1)
|
30
30
|
multi_json (~> 1.0)
|
31
31
|
arel (3.0.2)
|
32
|
-
blocks (2.
|
33
|
-
|
32
|
+
blocks (2.3.0)
|
33
|
+
call_with_params
|
34
34
|
rails (>= 3.0.0)
|
35
35
|
builder (3.0.4)
|
36
|
+
call_with_params (0.0.1)
|
37
|
+
activesupport (>= 3.0.0)
|
38
|
+
columnize (0.3.6)
|
39
|
+
debugger (1.6.1)
|
40
|
+
columnize (>= 0.3.1)
|
41
|
+
debugger-linecache (~> 1.2.0)
|
42
|
+
debugger-ruby_core_source (~> 1.2.3)
|
43
|
+
debugger-linecache (1.2.0)
|
44
|
+
debugger-ruby_core_source (1.2.3)
|
36
45
|
diff-lcs (1.2.1)
|
37
46
|
erubis (2.7.0)
|
38
47
|
git (1.2.5)
|
@@ -118,8 +127,9 @@ PLATFORMS
|
|
118
127
|
ruby
|
119
128
|
|
120
129
|
DEPENDENCIES
|
121
|
-
blocks (~> 2.
|
130
|
+
blocks (~> 2.3.0)
|
122
131
|
bundler (~> 1.3.5)
|
132
|
+
debugger
|
123
133
|
jeweler (~> 1.8.4)
|
124
134
|
mocha (= 0.10.3)
|
125
135
|
rails (>= 3.0.0)
|
data/README.rdoc
CHANGED
@@ -1,197 +1,150 @@
|
|
1
1
|
= table-for
|
2
2
|
|
3
|
-
|
3
|
+
TableFor is a table builder for a collection of domain objects. It very easily allows the user to specify the columns to render and to override how the table, the header columns, the rows, and the columns are rendered.
|
4
4
|
|
5
5
|
== Installation
|
6
6
|
|
7
|
-
In <b>Rails 3</b>, add this to your Gemfile.
|
8
|
-
|
9
|
-
gem "table-for"
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
<% table.column :
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
<%= table_for @users do |table| %>
|
39
|
-
<% table.column :email %>
|
40
|
-
<% table.column :first_name %>
|
41
|
-
<% table.column :last_name %>
|
42
|
-
<% end %>
|
43
|
-
|
44
|
-
Here, each column will send its respective column name to the user object: user.send(:email), user.send(:first_name), user.send(:last_name),
|
45
|
-
to determine what data to output in each column.
|
46
|
-
|
47
|
-
== Specifying the Label to Use for a Column
|
48
|
-
<%= table_for @users do |table| %>
|
49
|
-
<% table.column :email, :label => "Email Address" %>
|
50
|
-
<% end %>
|
51
|
-
|
52
|
-
== Overriding the Default Way of Rendering a Column
|
53
|
-
<%= table_for @users do |table| %>
|
54
|
-
<% table.column :name do |user| %>
|
55
|
-
<%= "#{user.first_name} #{user.last_name}" %>
|
56
|
-
<% end %>
|
57
|
-
<% end %>
|
58
|
-
|
59
|
-
<!-- Or, since the name of the column is no longer used to figure out what data to render: -->
|
60
|
-
<%= table_for @users do |table| %>
|
61
|
-
<% table.column :full_name do |user| %>
|
62
|
-
<%= "#{user.first_name} #{user.last_name}" %>
|
63
|
-
<% end %>
|
64
|
-
<% end %>
|
65
|
-
|
66
|
-
<!-- Or the block name could be removed altogether and replaced with a label: -->
|
67
|
-
<%= table_for @users do |table| %>
|
68
|
-
<% table.column :label => "Full Name" do |user| %>
|
7
|
+
In <b>Rails 3 or Rails 4</b>, add this to your Gemfile.
|
8
|
+
|
9
|
+
gem "table-for", :git => "git@github.com:hunterae/table-for.git"
|
10
|
+
|
11
|
+
== Example
|
12
|
+
The following example is purposely complex (in many cases, there are easier ways to do what is shown) in order to show a wide range of features that TableFor is capable of:
|
13
|
+
|
14
|
+
<%= table_for @users, :table_html => { :class => "table table-hover table-bordered" },
|
15
|
+
:sortable => true,
|
16
|
+
:sort_url => sort_admin_users_path,
|
17
|
+
:link_namespace => :admin,
|
18
|
+
:data_row_html => {
|
19
|
+
:class => lambda { cycle('success', 'error', 'warning', 'info')},
|
20
|
+
:id => lambda { |user| "user-#{user.id}" }} do |table| %>
|
21
|
+
<% table.column :data => "Modify", :link_action => :edit %>
|
22
|
+
<% table.column :data => "Show", :link_url => lambda { |user| admin_user_path(user) } %>
|
23
|
+
<% table.column :data => "Show 2.0", :link => true %>
|
24
|
+
<% table.column :email, :header => "Email Address" %>
|
25
|
+
<% table.column :first_name, :formatter => :downcase %>
|
26
|
+
<% table.column :last_name, :formatter => Proc.new { |last_name| last_name.upcase } %>
|
27
|
+
<% table.column :created_at, :formatter => [:strftime, "%m/%d/%y %I:%M %p"] %>
|
28
|
+
<% table.column :updated_at,
|
29
|
+
:header => Proc.new {
|
30
|
+
content_tag(:span, :class => "badge badge-success") do
|
31
|
+
"Last Updated"
|
32
|
+
end
|
33
|
+
},
|
34
|
+
:sortable => false,
|
35
|
+
:header_column_html => { :style => "background-color:orange" },
|
36
|
+
:data => Proc.new { time_ago_in_words table.current_row.updated_at } %>
|
37
|
+
<% table.column :full_name, :header => "Full Name", :order => "last_name, first_name" do |user| %>
|
69
38
|
<%= "#{user.first_name} #{user.last_name}" %>
|
70
39
|
<% end %>
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
<%= table_for @users, :sortable => true, :sort_url => users_path do |table| %>
|
76
|
-
<% table.column :id, :sortable => false %>
|
77
|
-
<% table.column :email %>
|
78
|
-
<% table.column :name, :order => "first_name,last_name" do |user| %>
|
79
|
-
<%= "#{user.first_name} #{user.last_name}" %>
|
40
|
+
<% table.header :full_name do |column, options| %>
|
41
|
+
<%= table.header_sort_link(column, options) do %>
|
42
|
+
<span class="label label-important">FULL NAME</span>
|
43
|
+
<% end %>
|
80
44
|
<% end %>
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
<% table.column :email, :sortable => true %>
|
87
|
-
<% table.column :name, :order => "first_name,last_name", :sortable => true do |user| %>
|
88
|
-
<%= "#{user.first_name} #{user.last_name}" %>
|
45
|
+
<% table.column :data => "Delete", :link_method => :delete, :link_confirm => "Are you sure?" %>
|
46
|
+
<% table.footer do %>
|
47
|
+
<div class="pull-right">
|
48
|
+
<%= will_paginate @users %>
|
49
|
+
</div>
|
89
50
|
<% end %>
|
90
51
|
<% end %>
|
91
52
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
53
|
+
Produces (with Twitter Bootstrap):
|
54
|
+
|
55
|
+
{<img src="https://raw.github.com/hunterae/table-for/master/example_table.png">}[http://example.com]
|
56
|
+
|
57
|
+
For detailed instructions on how to run this example, along with comments on every line of the above table, check out the {Example Details}[https://github.com/hunterae/table-for/blob/master/example.rdoc].
|
58
|
+
|
59
|
+
== table_for options
|
60
|
+
The first argument to the table_for call will always be the array of domain objects. The second argument is a hash
|
61
|
+
and is optional. It is any combination of the following options:
|
62
|
+
|
63
|
+
sortable::
|
64
|
+
(defaults to false)
|
65
|
+
Sets whether all columns are sortable by default.
|
66
|
+
If this field is set to true, each column header will be generated as a link.
|
67
|
+
sort_url::
|
68
|
+
(defaults to "")
|
69
|
+
Sets the url for the header column links. This will only affect columns that are sortable.
|
70
|
+
link_namespace::
|
71
|
+
(defaults to nil)
|
72
|
+
Sets the default namespace for any links generated in the columns.
|
73
|
+
For example, a link_namespace of admin would try to build links within the admin namespace in the routes.
|
74
|
+
This can be specified as a string, an array, a domain object, or a symbol,
|
75
|
+
i.e. :link_namespace => [:admin, @post, :comments]
|
76
|
+
table_html::
|
77
|
+
(defaults to nil)
|
78
|
+
Hash to specify the styles, classes, id, and other attributes applied to the table element,
|
79
|
+
i.e. :table_html => { :id => "my-table", :class => "table table-bordered", :cellpadding => 2 }.
|
80
|
+
thead_html::
|
81
|
+
(defaults to nil)
|
82
|
+
Hash to specify the styles, classes, id, and other attributes applied to the thead element,
|
83
|
+
i.e. :thead_html => { :id => "thead-id" }
|
84
|
+
Note: If TableFor.render_thead_element is set to false, the thead surrounding element for the
|
85
|
+
header row will not be rendered.
|
86
|
+
header_row_html::
|
87
|
+
(defaults to nil)
|
88
|
+
Hash to specify the styles, classes, id, and other attributes applied to the header row (tr) element,
|
89
|
+
i.e. :header_row_html => { :style => 'color: orange' }
|
90
|
+
header_column_html::
|
91
|
+
(defaults to {})
|
92
|
+
Hash to specify the styles, classes, id, and other attributes applied to the header column (th) element.
|
93
|
+
The values in this hash can each be a string or a Proc that takes (optionally) the column object as a parameter
|
94
|
+
i.e. :header_column => { :style => "font-weight: bold" }, or :header_column => { :class => Proc.new {|column| "#{column.name}_header" } }
|
95
|
+
tbody_html::
|
96
|
+
(defaults to nil)
|
97
|
+
Hash to specify the styles, classes, id, and other attributes applied to the tbody element,
|
98
|
+
i.e. :tbody_html => { :id => "body-id" }
|
99
|
+
Note: If TableFor.render_tbody_element is set to false, the tbody surrounding element for the
|
100
|
+
table data rows will not be rendered.
|
101
|
+
data_row_html::
|
102
|
+
(defaults to nil)
|
103
|
+
Hash to specify the styles, classes, id, and other attributes applied to each data row element (tr).
|
104
|
+
The values in this hash can each be a string or a Proc that takes (optionally) the current record as a parameter
|
105
|
+
i.e. :data_row_html => { :class => lambda { cycle('success', 'error', 'warning', 'info')}, :id => lambda { |user| "user-#{user.id}" } }
|
106
|
+
data_column_html::
|
107
|
+
(defaults to {})
|
108
|
+
Hash to specify the styles, classes, id, and other attributes applied to the header column (th) element.
|
109
|
+
The values in this hash can each be a string or a Proc that takes (optionally) the current_record and (also optionally) the column object as parameters
|
110
|
+
i.e. :data_column_html => { :style => "font-weight: bold", :id => Proc.new {|record, column| "record-#{record.id}-#{column.name}" } }
|
111
|
+
tfoot_html::
|
112
|
+
(defaults to nil)
|
113
|
+
Hash to specify the styles, classes, id, and other attributes applied to the tfoot element,
|
114
|
+
i.e. :tfoot_html => { :id => "tfoot-id" }
|
115
|
+
Note: If TableFor.render_tfoot_element is set to false, the tfoot surrounding element for the
|
116
|
+
footer row will not be rendered.
|
117
|
+
footer_row_html::
|
118
|
+
(defaults to nil)
|
119
|
+
Hash to specify the styles, classes, id, and other attributes applied to the footer row (tr) element,
|
120
|
+
i.e. :footer_row_html => { :style => 'color: orange' }
|
121
|
+
footer_column_html::
|
122
|
+
TODO
|
123
|
+
|
124
|
+
== table_for column options
|
125
|
+
data:: TODO
|
126
|
+
header:: TODO
|
127
|
+
formatter:: TODO
|
128
|
+
sortable:: TODO
|
129
|
+
sort_url:: TODO
|
130
|
+
order:: TODO
|
131
|
+
link_url:: TODO
|
132
|
+
link_action:: TODO
|
133
|
+
link_method:: TODO
|
134
|
+
link_confirm:: TODO
|
135
|
+
link_html::
|
136
|
+
link:: TODO
|
137
|
+
data_column_html:: TODO
|
138
|
+
header_column_html:: TODO
|
139
|
+
|
140
|
+
== table_for header options
|
141
|
+
TODO
|
142
|
+
|
143
|
+
== table_for footer options
|
144
|
+
TODO
|
145
|
+
|
146
|
+
== table_for configuration
|
147
|
+
TODO
|
151
148
|
|
152
149
|
== Using "Before" and "After" hooks
|
153
|
-
|
154
|
-
<%= table_for @users do |table| %>
|
155
|
-
<% table.column :email %>
|
156
|
-
<% table.define :footer do %>
|
157
|
-
<tfoot><tr><td colspan="<%= table.columns.length %>">My Footer</td></tr></tfoot>
|
158
|
-
<% end %>
|
159
|
-
<% end %>
|
160
|
-
|
161
|
-
<!-- Evaluating an expression before each row renders -->
|
162
|
-
<%= table_for @users do |table| %>
|
163
|
-
<% table.before :row do |user| %>
|
164
|
-
<!-- Perform some calculation -->
|
165
|
-
<% @evaluated_data = user.do_some_method %>
|
166
|
-
<% end %>
|
167
|
-
<% table.column :label => "First Column" do |user| %>
|
168
|
-
<!-- Use the stored value in some way -->
|
169
|
-
<%= @evaluated_data.method_1 %>
|
170
|
-
<% end %>
|
171
|
-
<% table.column :label => "Second Column" do |user| %>
|
172
|
-
<!-- Use the stored value in some other way -->
|
173
|
-
<%= @evaluated_data.method_2 %>
|
174
|
-
<% end %>
|
175
|
-
<% end %>
|
176
|
-
|
177
|
-
<!-- Adding a row before all the data rows -->
|
178
|
-
<%= table_for @users do |table| %>
|
179
|
-
<% table.before :rows do %>
|
180
|
-
<tr><td colspan="<%= table.columns.length %>">My First Row</td></tr>
|
181
|
-
<% end %>
|
182
|
-
<% table.column :email %>
|
183
|
-
<% end %>
|
184
|
-
|
185
|
-
== Changing the Default Way table_for Renders
|
186
|
-
<!-- Don't render thead and tbody tags -->
|
187
|
-
<%= table_for @users do |table| %>
|
188
|
-
<% table.define :table do |options| %>
|
189
|
-
<%= content_tag :table, options[:table_html] do %>
|
190
|
-
<!-- Instead of table.render :header, do this -->
|
191
|
-
<%= table.render :header_row %>
|
192
|
-
<!-- Instead of table.render :body, do this -->
|
193
|
-
<%= table.render :rows %>
|
194
|
-
<% end %>
|
195
|
-
<% end %>
|
196
|
-
<% table.column :email %>
|
197
|
-
<% end %>
|
150
|
+
TODO
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0
|
@@ -1,14 +1,18 @@
|
|
1
1
|
<% table.define :table do |options| %>
|
2
|
-
<%= content_tag :table,
|
2
|
+
<%= content_tag :table, table.table_html(options) do %>
|
3
3
|
<%= table.render :header %>
|
4
4
|
<%= table.render :body %>
|
5
|
-
<%# Purposely no default implementation for the tfoot block given, since most tables do not have footers
|
5
|
+
<%# Purposely no default implementation for the tfoot block given, since most tables do not have footers (provided to for easy hook to add a footer). %>
|
6
6
|
<%= table.render :footer %>
|
7
7
|
<% end %>
|
8
8
|
<% end %>
|
9
9
|
|
10
10
|
<% table.define :header do |options| %>
|
11
|
-
|
11
|
+
<% if TableFor.render_thead_element %>
|
12
|
+
<%= content_tag :thead, options[:thead_html] do %>
|
13
|
+
<%= table.render :header_row %>
|
14
|
+
<% end %>
|
15
|
+
<% else %>
|
12
16
|
<%= table.render :header_row %>
|
13
17
|
<% end %>
|
14
18
|
<% end %>
|
@@ -20,65 +24,64 @@
|
|
20
24
|
<% end %>
|
21
25
|
|
22
26
|
<% table.define :header_column do |column, options| %>
|
23
|
-
<%= content_tag :th,
|
27
|
+
<%= content_tag :th, table.header_column_html(column, options) do %>
|
24
28
|
<%= table.render "#{column.name}_header", column, column.options %>
|
25
29
|
<% end %>
|
26
30
|
<% end %>
|
27
31
|
|
28
|
-
<%# Define header blocks for the edit, show, and delete columns (i.e. we want those columns to display with a blank header) %>
|
29
|
-
<% [:edit, :show, :delete].each do |action| %>
|
30
|
-
<% table.define "#{action}_header", :label => false, :order => :id do |column, options| %>
|
31
|
-
<%= table_for_header_cell_data(column, options) %>
|
32
|
-
<% end %>
|
33
|
-
<% end %>
|
34
|
-
|
35
32
|
<%# Define a header block for each column, named using that column's name with the word "_header" appended to it %>
|
36
33
|
<% table.define lambda {|column| "#{column.name}_header" }, :collection => table.columns do |column, options| %>
|
37
|
-
<%=
|
34
|
+
<%= table.header_cell_content(column, options) %>
|
38
35
|
<% end %>
|
39
36
|
|
40
37
|
<% table.define :body do |options| %>
|
41
|
-
|
42
|
-
<%=
|
38
|
+
<% if TableFor.render_tbody_element %>
|
39
|
+
<%= content_tag :tbody, options[:tbody_html] do %>
|
40
|
+
<%= table.render :data_row, :collection => records %>
|
41
|
+
<% end %>
|
42
|
+
<% else %>
|
43
|
+
<%= table.render :data_row, :collection => records %>
|
43
44
|
<% end %>
|
44
45
|
<% end %>
|
45
46
|
|
46
|
-
<% table.define :
|
47
|
+
<% table.define :data_row do |record, options| %>
|
47
48
|
<% table.set_current_record(record) %>
|
48
|
-
<%= content_tag :tr,
|
49
|
-
<%= table.render :
|
49
|
+
<%= content_tag :tr, table.call_each_hash_value_with_params(options[:data_row_html], record) do %>
|
50
|
+
<%= table.render :data_column, record, :collection => table.columns %>
|
50
51
|
<% end %>
|
51
52
|
<% end %>
|
52
53
|
|
53
|
-
<% table.define :
|
54
|
-
<%= content_tag :td,
|
54
|
+
<% table.define :data_column do |column, record, options| %>
|
55
|
+
<%= content_tag :td, table.call_each_hash_value_with_params(options[:data_column_html], record, column) do %>
|
55
56
|
<%= table.render column.name, record, column, column.options %>
|
56
57
|
<% end %>
|
57
58
|
<% end %>
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
<%= link_to call_if_proc(link_name, record), url, options[:link_html] %>
|
60
|
+
<%# Define a block for each column, named using that column's name %>
|
61
|
+
<% table.define lambda {|column| column.name }, :collection => table.columns, :link_html => {} do |record, column, options| %>
|
62
|
+
<%= table.cell_content(record, column, options) %>
|
63
63
|
<% end %>
|
64
64
|
|
65
|
-
<% table.define :
|
66
|
-
<%
|
67
|
-
|
68
|
-
|
69
|
-
<% end %>
|
65
|
+
<% table.define :footer do |options| %>
|
66
|
+
<% if TableFor.render_tfoot_element %>
|
67
|
+
<%= content_tag :tfoot, options[:tfoot_html] do %>
|
68
|
+
<%= table.render :footer_row %>
|
69
|
+
<% end %>
|
70
|
+
<% else %>
|
71
|
+
<%= table.render :footer_row %>
|
72
|
+
<% end %>
|
73
|
+
<% end if table.defined?(:footer_content) %>
|
70
74
|
|
71
|
-
<% table.define :
|
72
|
-
|
73
|
-
|
74
|
-
<%
|
75
|
-
|
76
|
-
<%= link_to call_if_proc(link_name, record), url, {:method => method, :confirm => confirm}.merge(options[:link_html]) %>
|
77
|
-
<% end %>
|
75
|
+
<% table.define :footer_row do |options| %>
|
76
|
+
<%= content_tag :tr, options[:footer_row_html] do %>
|
77
|
+
<%= table.render :footer_column %>
|
78
|
+
<% end %>
|
79
|
+
<% end if table.defined?(:footer_content) %>
|
78
80
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
<% end %>
|
81
|
+
<% table.define :footer_column do |options| %>
|
82
|
+
<%= content_tag :td, {:colspan => table.columns.length}.merge(table.blocks[:footer_content].options[:footer_column_html] || {}) do %>
|
83
|
+
<%= table.render :footer_content %>
|
84
|
+
<% end %>
|
85
|
+
<% end if table.defined?(:footer_content) %>
|
83
86
|
|
84
87
|
<%= table.render :table %>
|