/
index_as_table.rb
323 lines (313 loc) · 9.51 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
# frozen_string_literal: true
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: "preview-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
# ```
#
# ## 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.
#
# You can pass the key specifying 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
# ```
#
# You can also define associated objects to include outside of the
# `scoped_collection` method:
#
# ```ruby
# includes :publisher
# ```
#
# 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)
add_class "index-as-table"
table_options = {
id: "index_table_#{active_admin_config.resource_name.plural}",
sortable: true,
i18n: active_admin_config.resource_class,
paginator: page_presenter[:paginator] != false,
row_class: page_presenter[:row_class]
}
if page_presenter.block
insert_tag(IndexTableFor, collection, table_options) do |t|
instance_exec(t, &page_presenter.block)
end
else
render "index_as_table_default", table_options: table_options
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(**options)
return unless active_admin_config.batch_actions.any?
column resource_selection_toggle_cell, class: options[:class], sortable: false do |resource|
resource_selection_cell resource
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)
elsif controller.action_methods.include?("edit")
link_to resource.id, edit_resource_path(resource)
else
resource.id
end
end
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
#
# ```
def actions(options = {}, &block)
name = options.delete(:name) { "" }
defaults = options.delete(:defaults) { true }
column name, options do |resource|
insert_tag(TableActions, class: "data-table-resource-actions") do
render "index_table_actions_default", defaults_data(resource) if defaults
if block
block_result = instance_exec(resource, &block)
text_node block_result unless block_result.is_a? Arbre::Element
end
end
end
end
private
def defaults_data(resource)
localizer = ActiveAdmin::Localizers.resource(active_admin_config)
{
resource: resource,
view_label: localizer.t(:view),
edit_label: localizer.t(:edit),
delete_label: localizer.t(:delete),
delete_confirmation_text: localizer.t(:delete_confirmation)
}
end
class TableActions < ActiveAdmin::Component
def item *args, **kwargs
text_node link_to(*args, **kwargs)
end
end
end # IndexTableFor
end
end
end