effective_datatables 1.8.2 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +72 -77
- data/app/models/effective/active_record_datatable_tool.rb +10 -8
- data/app/models/effective/datatable.rb +29 -30
- data/lib/effective_datatables/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51442e1874c5619504602bba266af6ebdd589a2a
|
4
|
+
data.tar.gz: 51f2e7929b20e801d9b6b30b70fd4c0c028503d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06f07d33e9eaf67ea873f21650b505338e1928a31ce5138264aa5eed6cb1715b8c84c0916a2ea2c7ba0d08443e22cbd0c6acbaf4a9bcfde8cfa1bc320b09d166
|
7
|
+
data.tar.gz: 055b33ce39c9b1745c74f73d105f4d16134e0bdea5c1e5e7587ccda73bbfa815826499c8166a3144b2f9acc548718df71117af048bac4b56f99a042162c42e90
|
data/README.md
CHANGED
@@ -201,12 +201,46 @@ def query_total
|
|
201
201
|
end
|
202
202
|
```
|
203
203
|
|
204
|
+
### Array Backed collection
|
205
|
+
|
206
|
+
Don't want to use ActiveRecord? Not a problem.
|
207
|
+
|
208
|
+
Define your collection as an Array of Arrays, declare only array_columns, and everything works as expected.
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
module Effective
|
212
|
+
module Datatables
|
213
|
+
class ArrayBackedDataTable < Effective::Datatable
|
214
|
+
array_column :id
|
215
|
+
array_column :first_name
|
216
|
+
array_column :last_name
|
217
|
+
array_column :email
|
218
|
+
|
219
|
+
def collection
|
220
|
+
[
|
221
|
+
[1, 'Dana', 'Janssen', 'dana@agilestyle.com'],
|
222
|
+
[2, 'Ashley', 'Janssen', 'ashley@agilestyle.com'],
|
223
|
+
[3, 'Matthew', 'Riemer', 'matthew@agilestyle.com'],
|
224
|
+
[4, 'Stephen', 'Brown', 'stephen@agilestyle.com'],
|
225
|
+
[5, 'Warren', 'Uhrich', 'warren@agilestyle.com'],
|
226
|
+
[6, 'Dallas', 'Meidinger', 'dallas@agilestyle.com'],
|
227
|
+
[7, 'Nathan', 'Feaver', 'nathan@agilestyle.com']
|
228
|
+
]
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
```
|
235
|
+
|
204
236
|
## table_column
|
205
237
|
|
206
238
|
This is the main DSL method that you will interact with.
|
207
239
|
|
208
240
|
table_column defines a 1:1 mapping between a SQL database table column and a frontend jQuery Datatables table column. It creates a column.
|
209
241
|
|
242
|
+
table_column performs searching and sorting on the raw database records, before any results are rendered.
|
243
|
+
|
210
244
|
Options may be passed to specify the display, search, sort and filter behaviour for that column.
|
211
245
|
|
212
246
|
When the given name of the table_column matches an ActiveRecord attribute, the options are set intelligently based on the underlying datatype.
|
@@ -239,7 +273,24 @@ table_column :user_id, :if => Proc.new { attributes[:user_id].blank? }, :filter
|
|
239
273
|
end
|
240
274
|
```
|
241
275
|
|
242
|
-
All table_columns are
|
276
|
+
All table_columns are `visible: true`, `sortable: true` by default.
|
277
|
+
|
278
|
+
## array_column
|
279
|
+
|
280
|
+
`array_column` accepts the same options as `table_column` and behaves identically on the frontend.
|
281
|
+
|
282
|
+
The difference occurs with sorting and filtering:
|
283
|
+
|
284
|
+
array_columns perform searching and sorting on the computed results after all columns have been rendered.
|
285
|
+
|
286
|
+
With a `table_column`, the frontend sends some search terms to the server, the raw database table is searched & sorted using standard ActiveRecord .where(), the appropriate rows returned, and then each row is rendered as per the rendering options.
|
287
|
+
|
288
|
+
With an `array_column`, the front end sends some search terms to the server, all rows are returned and rendered, and then the rendered output is searched & sorted.
|
289
|
+
|
290
|
+
This allows the output of an `array_column` to be anything complex that cannot be easily computed from the database.
|
291
|
+
|
292
|
+
When searching & sorting with a mix of table_columns and array_columns, all the table_columns are processed first so the most work is put on the database, the least on rails.
|
293
|
+
|
243
294
|
|
244
295
|
### General Options
|
245
296
|
|
@@ -351,7 +402,7 @@ The request object is available to the table_column, so you could just as easily
|
|
351
402
|
request.referer.include?('/admin/')
|
352
403
|
```
|
353
404
|
|
354
|
-
### Header Rendering
|
405
|
+
### Column Header Rendering Options
|
355
406
|
|
356
407
|
You can override the default rendering and define a partial to use for the header `<th>`:
|
357
408
|
|
@@ -376,21 +427,6 @@ Quickly create multiple table_columns all with default options:
|
|
376
427
|
table_columns :id, :created_at, :updated_at, :category, :title
|
377
428
|
```
|
378
429
|
|
379
|
-
## array_column
|
380
|
-
|
381
|
-
`array_column` accepts the same options as `table_column` and behaves identically on the frontend.
|
382
|
-
|
383
|
-
The difference occurs with sorting and filtering:
|
384
|
-
|
385
|
-
With a `table_column`, the frontend sends some search terms to the server, the raw database table is searched & sorted using standard ActiveRecord .where(), the appropriate rows returned, and then each row is rendered as per the rendering options.
|
386
|
-
|
387
|
-
With an `array_column`, the front end sends some search terms to the server, all rows are returned and rendered, and then the rendered output is searched & sorted.
|
388
|
-
|
389
|
-
This allows the output of an `array_column` to be anything complex that cannot be easily computed from the database.
|
390
|
-
|
391
|
-
When searching & sorting with a mix of table_columns and array_columns, all the table_columns are processed first so the most work is put on the database, the least on rails.
|
392
|
-
|
393
|
-
|
394
430
|
## default_order
|
395
431
|
|
396
432
|
Sort the table by this field and direction on start up
|
@@ -414,43 +450,11 @@ Valid options are `10, 25, 50, 100, 250, 1000, :all`
|
|
414
450
|
|
415
451
|
There are a few other ways to customize the behaviour of effective_datatables
|
416
452
|
|
417
|
-
### Display of an Empty Datatable
|
418
|
-
|
419
|
-
How an empty datatable (0 display records) is displayed depends on how `render_datatable` is called.
|
420
|
-
|
421
|
-
To render the full datatable with the default 'No data available in table' message:
|
422
|
-
|
423
|
-
```haml
|
424
|
-
= render_datatable(@datatable)
|
425
|
-
```
|
426
|
-
|
427
|
-
To skip rendering the datatable and just output a custom message:
|
428
|
-
|
429
|
-
```haml
|
430
|
-
= render_datatable(@datatable, 'There are no posts.')
|
431
|
-
```
|
432
|
-
|
433
|
-
or
|
434
|
-
|
435
|
-
```haml
|
436
|
-
= render_datatable(@datatable, :empty => 'There are no posts.')
|
437
|
-
```
|
438
|
-
|
439
|
-
To skip rendering the datatable and instead render given content:
|
440
|
-
|
441
|
-
```haml
|
442
|
-
= render_datatable(@datatable) do
|
443
|
-
%p There are no posts.
|
444
|
-
%p
|
445
|
-
Have a picture of a cat instead
|
446
|
-
= image_tag('cat.png')
|
447
|
-
```
|
448
|
-
|
449
453
|
### Checking for Empty collection
|
450
454
|
|
451
|
-
|
455
|
+
Check whether the datatable has records by calling `@datatable.empty?` and `@datatable.present?`.
|
452
456
|
|
453
|
-
Keep in mind, these methods look at the collection's total records,
|
457
|
+
Keep in mind, these methods look at the collection's total records, not the currently displayed/filtered records.
|
454
458
|
|
455
459
|
|
456
460
|
### Customize Filter Behaviour
|
@@ -566,37 +570,28 @@ module Effective
|
|
566
570
|
end
|
567
571
|
```
|
568
572
|
|
569
|
-
##
|
573
|
+
## Working with other effective_gems
|
570
574
|
|
571
|
-
|
575
|
+
### Effective Obfuscation
|
572
576
|
|
573
|
-
|
577
|
+
When working with an ActiveRecord collection that implements [effective_obfuscation](https://github.com/code-and-effect/effective_obfuscation) for the ID column,
|
578
|
+
that column's filters and sorting will be automatically configured.
|
574
579
|
|
575
|
-
|
576
|
-
module Effective
|
577
|
-
module Datatables
|
578
|
-
class ArrayBackedDataTable < Effective::Datatable
|
579
|
-
array_column :id
|
580
|
-
array_column :first_name
|
581
|
-
array_column :last_name
|
582
|
-
array_column :email
|
580
|
+
Just define `table_column :id`.
|
583
581
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
582
|
+
Unfortunately, due to the effective_obfuscation algorithm, sorting and filtering by partial values is not supported.
|
583
|
+
|
584
|
+
So the column may not be sorted, and may only be filtered by typing the entire 10-digit number, with or without any formatting.
|
585
|
+
|
586
|
+
### Effective Roles
|
587
|
+
|
588
|
+
When working with an ActiveRecord collection that implements [effective_roles](https://github.com/code-and-effect/effective_roles),
|
589
|
+
the filters and sorting will be automatically configured.
|
590
|
+
|
591
|
+
Just define `table_column :roles`.
|
592
|
+
|
593
|
+
The `EffectiveRoles.roles` collection will be used for the filter values, and sorting will be done by roles_mask.
|
595
594
|
|
596
|
-
end
|
597
|
-
end
|
598
|
-
end
|
599
|
-
```
|
600
595
|
|
601
596
|
## Get access to the raw results
|
602
597
|
|
@@ -42,9 +42,9 @@ module Effective
|
|
42
42
|
case table_column[:type]
|
43
43
|
when :string, :text
|
44
44
|
if table_column[:filter][:type] == :select && table_column[:filter][:fuzzy] != true
|
45
|
-
collection.where("#{column} = :term", :
|
45
|
+
collection.where("#{column} = :term", term: term)
|
46
46
|
else
|
47
|
-
collection.where("#{column} ILIKE :term", :
|
47
|
+
collection.where("#{column} ILIKE :term", term: "%#{term}%")
|
48
48
|
end
|
49
49
|
when :datetime
|
50
50
|
begin
|
@@ -68,22 +68,24 @@ module Effective
|
|
68
68
|
end_at = start_at
|
69
69
|
end
|
70
70
|
|
71
|
-
collection.where("#{column} >= :start_at AND #{column} <= :end_at", :
|
71
|
+
collection.where("#{column} >= :start_at AND #{column} <= :end_at", start_at: start_at, end_at: end_at)
|
72
72
|
rescue => e
|
73
73
|
collection
|
74
74
|
end
|
75
75
|
when :obfuscated_id
|
76
76
|
if (deobfuscated_id = collection.deobfuscate(term)) == term # We weren't able to deobfuscate it, so this is an Invalid ID
|
77
|
-
collection.where("#{column} = :term", :
|
77
|
+
collection.where("#{column} = :term", term: 0)
|
78
78
|
else
|
79
|
-
collection.where("#{column} = :term", :
|
79
|
+
collection.where("#{column} = :term", term: deobfuscated_id)
|
80
80
|
end
|
81
|
+
when :effective_roles
|
82
|
+
collection.with_role(term)
|
81
83
|
when :integer
|
82
|
-
collection.where("#{column} = :term", :
|
84
|
+
collection.where("#{column} = :term", term: term.to_i)
|
83
85
|
when :year
|
84
|
-
collection.where("EXTRACT(YEAR FROM #{column}) = :term", :
|
86
|
+
collection.where("EXTRACT(YEAR FROM #{column}) = :term", term: term.to_i)
|
85
87
|
else
|
86
|
-
collection.where("#{column} = :term", :
|
88
|
+
collection.where("#{column} = :term", term: term)
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
@@ -355,6 +355,8 @@ module Effective
|
|
355
355
|
val = (obj.send(name) rescue nil).to_s
|
356
356
|
elsif opts[:type] == :obfuscated_id
|
357
357
|
(obj.send(:to_param) rescue nil).to_s
|
358
|
+
elsif opts[:type] == :effective_roles
|
359
|
+
(obj.send(:roles) rescue []).join(', ')
|
358
360
|
else
|
359
361
|
val = (obj.send(name) rescue nil)
|
360
362
|
val = (obj[opts[:array_index]] rescue nil) if val == nil
|
@@ -365,9 +367,7 @@ module Effective
|
|
365
367
|
case value
|
366
368
|
when Date
|
367
369
|
value.strftime(EffectiveDatatables.date_format)
|
368
|
-
when Time
|
369
|
-
value.strftime(EffectiveDatatables.datetime_format)
|
370
|
-
when DateTime
|
370
|
+
when Time, DateTime
|
371
371
|
value.strftime(EffectiveDatatables.datetime_format)
|
372
372
|
else
|
373
373
|
value.to_s
|
@@ -429,7 +429,7 @@ module Effective
|
|
429
429
|
cols.each_with_index do |(name, _), index|
|
430
430
|
# If this is a belongs_to, add an :if clause specifying a collection scope if
|
431
431
|
if belong_tos.key?(name)
|
432
|
-
cols[name][:if] ||= Proc.new { attributes[belong_tos[name][:foreign_key]].blank? }
|
432
|
+
cols[name][:if] ||= Proc.new { attributes[belong_tos[name][:foreign_key]].blank? }
|
433
433
|
end
|
434
434
|
|
435
435
|
sql_column = (collection.columns rescue []).find do |column|
|
@@ -443,14 +443,22 @@ module Effective
|
|
443
443
|
cols[name][:column] ||= (sql_table && sql_column) ? "\"#{sql_table.name}\".\"#{sql_column.name}\"" : name
|
444
444
|
cols[name][:width] ||= nil
|
445
445
|
cols[name][:sortable] = true if cols[name][:sortable] == nil
|
446
|
-
cols[name][:type] ||= (belong_tos.key?(name) ? :belongs_to :
|
446
|
+
cols[name][:type] ||= (belong_tos.key?(name) ? :belongs_to : sql_column.try(:type).presence) || :string
|
447
447
|
cols[name][:class] = "col-#{cols[name][:type]} col-#{name} #{cols[name][:class]}".strip
|
448
448
|
|
449
|
-
|
449
|
+
# EffectiveObfuscation
|
450
|
+
if name == 'id' && defined?(EffectiveObfuscation) && collection.respond_to?(:deobfuscate)
|
450
451
|
cols[name][:sortable] = false
|
451
452
|
cols[name][:type] = :obfuscated_id
|
452
453
|
end
|
453
454
|
|
455
|
+
# EffectiveRoles, if you do table_column :roles, everything just works
|
456
|
+
if name == 'roles' && defined?(EffectiveRoles) && collection.respond_to?(:with_role)
|
457
|
+
cols[name][:sortable] = true
|
458
|
+
cols[name][:column] = sql_table.present? ? "\"#{sql_table.name}\".\"roles_mask\"" : name
|
459
|
+
cols[name][:type] = :effective_roles
|
460
|
+
end
|
461
|
+
|
454
462
|
if sql_table.present? && sql_column.blank? # This is a SELECT AS column
|
455
463
|
cols[name][:sql_as_column] = true
|
456
464
|
end
|
@@ -464,38 +472,29 @@ module Effective
|
|
464
472
|
end
|
465
473
|
|
466
474
|
def initialize_table_column_filter(filter, col_type, belongs_to)
|
467
|
-
return {:
|
468
|
-
|
469
|
-
if filter.kind_of?(
|
470
|
-
|
471
|
-
elsif filter.kind_of?(String)
|
472
|
-
filter = HashWithIndifferentAccess.new(:type => filter.to_sym)
|
473
|
-
elsif filter.kind_of?(Hash) == false
|
474
|
-
filter = HashWithIndifferentAccess.new()
|
475
|
-
end
|
475
|
+
return {type: :null} if filter == false
|
476
|
+
|
477
|
+
filter = {type: filter.to_sym} if filter.kind_of?(String)
|
478
|
+
filter = {} unless filter.kind_of?(Hash)
|
476
479
|
|
477
480
|
# This is a fix for passing filter[:selected] == false, it needs to be 'false'
|
478
481
|
filter[:selected] = filter[:selected].to_s unless filter[:selected].nil?
|
479
482
|
|
480
|
-
|
483
|
+
case col_type
|
481
484
|
when :belongs_to
|
482
|
-
|
483
|
-
:
|
484
|
-
:
|
485
|
-
|
485
|
+
{
|
486
|
+
type: :select,
|
487
|
+
values: Proc.new { belongs_to[:klass].all.map { |obj| [obj.to_s, obj.id] }.sort { |x, y| x[1] <=> y[1] } }
|
488
|
+
}
|
489
|
+
when :effective_roles
|
490
|
+
{type: :select, values: EffectiveRoles.roles}
|
486
491
|
when :integer
|
487
|
-
|
492
|
+
{type: :number}
|
488
493
|
when :boolean
|
489
|
-
|
494
|
+
{type: :boolean, values: [true, false]}
|
490
495
|
else
|
491
|
-
|
492
|
-
end
|
493
|
-
|
494
|
-
if filter[:type] == :boolean
|
495
|
-
filter = HashWithIndifferentAccess.new(:values => [true, false]).merge(filter)
|
496
|
-
end
|
497
|
-
|
498
|
-
filter
|
496
|
+
{type: :string}
|
497
|
+
end.merge(filter.symbolize_keys)
|
499
498
|
end
|
500
499
|
|
501
500
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_datatables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.
|
4
|
+
version: 1.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06
|
11
|
+
date: 2015-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|