/
index_as_table.rb
391 lines (372 loc) · 12.3 KB
/
index_as_table.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
module ActiveAdmin
module Views
# # Index as a Table
#
# By default, the index page is a table with each of the models content columns and links to
# show, edit and delete the object. There are many ways to customize what gets
# displayed.
#
# ## Defining Columns
#
# To display an attribute or a method on a resource, simply pass a symbol into the
# column method:
#
# ```ruby
# index do
# selectable_column
# column :title
# end
# ```
#
# For association columns we make an educated guess on what to display by
# calling the following methods in the following order:
#
# ```ruby
# :display_name, :full_name, :name, :username, :login, :title, :email, :to_s
# ```
#
# This can be customized in `config/initializers/active_admin.rb`.
#
# If the default title does not work for you, pass it as the first argument:
#
# ```ruby
# index do
# selectable_column
# column "My Custom Title", :title
# end
# ```
#
# Sometimes that just isn't enough and you need to write some view-specific code.
# For example, say we wanted a "Title" column that links to the posts admin screen.
#
# `column` accepts a block that will be rendered for each of the objects in the collection.
# The block is called once for each resource, which is passed as an argument to the block.
#
# ```ruby
# index do
# selectable_column
# column "Title" do |post|
# link_to post.title, admin_post_path(post)
# end
# end
# ```
#
# ## Defining Actions
#
# To setup links to View, Edit and Delete a resource, use the `actions` method:
#
# ```ruby
# index do
# selectable_column
# column :title
# actions
# end
# ```
#
# You can also append custom links to the default links:
#
# ```ruby
# index do
# selectable_column
# column :title
# actions do |post|
# item "Preview", admin_preview_post_path(post), class: "member_link"
# end
# end
# ```
#
# Or forego the default links entirely:
#
# ```ruby
# index do
# column :title
# actions defaults: false do |post|
# item "View", admin_post_path(post)
# end
# end
# ```
#
# Or append custom action with custom html via arbre:
#
# ```ruby
# index do
# column :title
# actions do |post|
# a "View", href: admin_post_path(post)
# end
# end
# ```
#
# In case you prefer to list actions links in a dropdown menu:
#
# ```ruby
# index do
# selectable_column
# column :title
# actions dropdown: true do |post|
# item "Preview", admin_preview_post_path(post)
# end
# end
# ```
#
# In addition, you can insert the position of the row in the greater collection by using the index_column special command:
#
# ```ruby
# index do
# selectable_column
# index_column
# column :title
# end
# ```
#
# index_column take an optional offset parameter to allow a developer to set the starting number for the index (default is 1).
#
# ## Sorting
#
# When a column is generated from an Active Record attribute, the table is
# sortable by default. If you are creating a custom column, you may need to give
# Active Admin a hint for how to sort the table.
#
# If a column is defined using a block, you must pass the key to turn on sorting. The key
# is the attribute which gets used to sort objects using Active Record.
#
# By default, this is the column on the resource's table that the attribute corresponds to.
# Otherwise, any attribute that the resource collection responds to can be used.
#
# ```ruby
# index do
# column :title, sortable: :title do |post|
# link_to post.title, admin_post_path(post)
# end
# end
# ```
#
# You can turn off sorting on any column by passing false:
#
# ```ruby
# index do
# column :title, sortable: false
# end
# ```
#
# It's also possible to sort by PostgreSQL's hstore column key. You should set `sortable`
# option to a `column->'key'` value:
#
# ```ruby
# index do
# column :keywords, sortable: "meta->'keywords'"
# end
# ```
#
# ## Custom sorting
#
# It is also possible to use database specific expressions and options for sorting by column
#
# ```ruby
# order_by(:title) do |order_clause|
# if order_clause.order == 'desc'
# [order_clause.to_sql, 'NULLS LAST'].join(' ')
# else
# [order_clause.to_sql, 'NULLS FIRST'].join(' ')
# end
# end
#
# index do
# column :title
# end
# ```
#
# ## Associated Sorting
#
# You're normally able to sort columns alphabetically, but by default you
# can't sort by associated objects. Though with a few simple changes, you can.
#
# Assuming you're on the Books index page, and Book has_one Publisher:
#
# ```ruby
# controller do
# def scoped_collection
# super.includes :publisher # prevents N+1 queries to your database
# end
# end
# ```
#
# Then it's simple to sort by any Publisher attribute from within the index table:
#
# ```ruby
# index do
# column :publisher, sortable: 'publishers.name'
# end
# ```
#
# ## Showing and Hiding Columns
#
# The entire index block is rendered within the context of the view, so you can
# easily do things that show or hide columns based on the current context.
#
# For example, if you were using CanCan:
#
# ```ruby
# index do
# column :title, sortable: false
# column :secret_data if can? :manage, Post
# end
# ```
#
# ## Custom row class
#
# In order to add special class to table rows pass the proc object as a `:row_class` option
# of the `index` method.
#
# ```ruby
# index row_class: ->elem { 'active' if elem.active? } do
# # columns
# end
# ```
#
class IndexAsTable < ActiveAdmin::Component
def build(page_presenter, collection)
table_options = {
id: "index_table_#{active_admin_config.resource_name.plural}",
sortable: true,
class: "index_table index",
i18n: active_admin_config.resource_class,
paginator: page_presenter[:paginator] != false,
row_class: page_presenter[:row_class]
}
table_for collection, table_options do |t|
table_config_block = page_presenter.block || default_table
instance_exec(t, &table_config_block)
end
end
def table_for(*args, &block)
insert_tag IndexTableFor, *args, &block
end
def default_table
proc do
selectable_column
id_column if resource_class.primary_key
active_admin_config.resource_columns.each do |attribute|
column attribute
end
actions
end
end
def self.index_name
"table"
end
#
# Extend the default ActiveAdmin::Views::TableFor with some
# methods for quickly displaying items on the index page
#
class IndexTableFor < ::ActiveAdmin::Views::TableFor
# Display a column for checkbox
def selectable_column
return unless active_admin_config.batch_actions.any?
column resource_selection_toggle_cell, class: 'col-selectable', sortable: false do |resource|
resource_selection_cell resource
end
end
def index_column(start_value = 1)
column '#', class: 'col-index', sortable: false do |resource|
@collection.offset_value + @collection.index(resource) + start_value
end
end
# Display a column for the id
def id_column
raise "#{resource_class.name} has no primary_key!" unless resource_class.primary_key
column(resource_class.human_attribute_name(resource_class.primary_key), sortable: resource_class.primary_key) do |resource|
if controller.action_methods.include?('show')
link_to resource.id, resource_path(resource), class: "resource_id_link"
elsif controller.action_methods.include?('edit')
link_to resource.id, edit_resource_path(resource), class: "resource_id_link"
else
resource.id
end
end
end
def default_actions
raise '`default_actions` is no longer provided in ActiveAdmin 1.x. Use `actions` instead.'
end
# Add links to perform actions.
#
# ```ruby
# # Add default links.
# actions
#
# # Add default links with a custom column title (empty by default).
# actions name: 'A title!'
#
# # Append some actions onto the end of the default actions.
# actions do |admin_user|
# item 'Grant Admin', grant_admin_admin_user_path(admin_user)
# item 'Grant User', grant_user_admin_user_path(admin_user)
# end
#
# # Append some actions onto the end of the default actions using arbre dsl.
# actions do |admin_user|
# a 'Grant Admin', href: grant_admin_admin_user_path(admin_user)
# end
#
# # Custom actions without the defaults.
# actions defaults: false do |admin_user|
# item 'Grant Admin', grant_admin_admin_user_path(admin_user)
# end
#
# # Append some actions onto the end of the default actions displayed in a Dropdown Menu
# actions dropdown: true do |admin_user|
# item 'Grant Admin', grant_admin_admin_user_path(admin_user)
# end
#
# # Custom actions without the defaults displayed in a Dropdown Menu.
# actions defaults: false, dropdown: true, dropdown_name: 'Additional actions' do |admin_user|
# item 'Grant Admin', grant_admin_admin_user_path(admin_user)
# end
#
# ```
def actions(options = {}, &block)
name = options.delete(:name) { '' }
defaults = options.delete(:defaults) { true }
dropdown = options.delete(:dropdown) { false }
dropdown_name = options.delete(:dropdown_name) { I18n.t 'active_admin.dropdown_actions.button_label', default: 'Actions' }
options[:class] ||= 'col-actions'
column name, options do |resource|
if dropdown
dropdown_menu dropdown_name do
defaults(resource) if defaults
instance_exec(resource, &block) if block_given?
end
else
table_actions do
defaults(resource, css_class: :member_link) if defaults
if block_given?
block_result = instance_exec(resource, &block)
text_node block_result unless block_result.is_a? Arbre::Element
end
end
end
end
end
private
def defaults(resource, options = {})
if controller.action_methods.include?('show') && authorized?(ActiveAdmin::Auth::READ, resource)
item I18n.t('active_admin.view'), resource_path(resource), class: "view_link #{options[:css_class]}", title: I18n.t('active_admin.view')
end
if controller.action_methods.include?('edit') && authorized?(ActiveAdmin::Auth::UPDATE, resource)
item I18n.t('active_admin.edit'), edit_resource_path(resource), class: "edit_link #{options[:css_class]}", title: I18n.t('active_admin.edit')
end
if controller.action_methods.include?('destroy') && authorized?(ActiveAdmin::Auth::DESTROY, resource)
item I18n.t('active_admin.delete'), resource_path(resource), class: "delete_link #{options[:css_class]}", title: I18n.t('active_admin.delete'),
method: :delete, data: {confirm: I18n.t('active_admin.delete_confirmation')}
end
end
class TableActions < ActiveAdmin::Component
builder_method :table_actions
def item *args
text_node link_to *args
end
end
end # IndexTableFor
end
end
end