effective_datatables 1.8.2 → 1.8.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|