ajax-datatables-rails 0.4.0 → 0.4.1
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 +5 -5
- data/.rubocop.yml +23 -1132
- data/.travis.yml +36 -24
- data/Appraisals +14 -8
- data/CHANGELOG.md +32 -7
- data/Gemfile +2 -0
- data/README.md +400 -335
- data/Rakefile +2 -1
- data/ajax-datatables-rails.gemspec +8 -6
- data/doc/webpack.md +50 -0
- data/gemfiles/{rails_4.1.15.gemfile → rails_4.1.16.gemfile} +1 -1
- data/gemfiles/{rails_4.2.8.gemfile → rails_4.2.10.gemfile} +2 -1
- data/gemfiles/{rails_5.0.3.gemfile → rails_5.0.7.gemfile} +1 -1
- data/gemfiles/{rails_5.1.1.gemfile → rails_5.1.6.gemfile} +1 -1
- data/gemfiles/rails_5.2.0.gemfile +13 -0
- data/lib/ajax-datatables-rails.rb +3 -11
- data/lib/ajax-datatables-rails/base.rb +44 -24
- data/lib/ajax-datatables-rails/config.rb +3 -0
- data/lib/ajax-datatables-rails/datatable/column.rb +33 -125
- data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +77 -0
- data/lib/ajax-datatables-rails/datatable/column/order.rb +29 -0
- data/lib/ajax-datatables-rails/datatable/column/search.rb +88 -0
- data/lib/ajax-datatables-rails/datatable/datatable.rb +10 -7
- data/lib/ajax-datatables-rails/datatable/simple_order.rb +17 -2
- data/lib/ajax-datatables-rails/datatable/simple_search.rb +3 -0
- data/lib/ajax-datatables-rails/orm/active_record.rb +14 -5
- data/lib/ajax-datatables-rails/version.rb +3 -1
- data/lib/ajax_datatables_rails.rb +15 -0
- data/lib/generators/datatable/config_generator.rb +2 -0
- data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +5 -0
- data/lib/generators/rails/datatable_generator.rb +6 -5
- data/lib/generators/rails/templates/datatable.rb +1 -15
- data/spec/ajax-datatables-rails/base_spec.rb +23 -26
- data/spec/ajax-datatables-rails/datatable/column_spec.rb +68 -23
- data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +1 -1
- data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +29 -2
- data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +1 -1
- data/spec/ajax-datatables-rails/extended_spec.rb +3 -3
- data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +94 -35
- data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +6 -6
- data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +43 -0
- data/spec/ajax-datatables-rails/orm/active_record_spec.rb +1 -1
- data/spec/factories/user.rb +1 -1
- data/spec/install_oracle.sh +2 -2
- data/spec/spec_helper.rb +8 -3
- data/spec/support/datatable_cond_date.rb +5 -0
- data/spec/support/datatable_cond_numeric.rb +41 -0
- data/spec/support/datatable_cond_proc.rb +11 -0
- data/spec/support/datatable_cond_string.rb +23 -0
- data/spec/support/datatable_order_nulls_last.rb +5 -0
- data/spec/support/test_helpers.rb +13 -88
- metadata +28 -13
- data/lib/ajax-datatables-rails/datatable/column_date_filter.rb +0 -41
data/.travis.yml
CHANGED
@@ -3,42 +3,52 @@ language: ruby
|
|
3
3
|
sudo: required
|
4
4
|
cache: bundler
|
5
5
|
rvm:
|
6
|
-
- 2.2.
|
7
|
-
- 2.3.
|
6
|
+
- 2.2.10
|
7
|
+
- 2.3.7
|
8
8
|
gemfile:
|
9
9
|
- gemfiles/rails_4.0.13.gemfile
|
10
|
-
- gemfiles/rails_4.1.
|
11
|
-
- gemfiles/rails_4.2.
|
12
|
-
- gemfiles/rails_5.0.
|
13
|
-
- gemfiles/rails_5.1.
|
10
|
+
- gemfiles/rails_4.1.16.gemfile
|
11
|
+
- gemfiles/rails_4.2.10.gemfile
|
12
|
+
- gemfiles/rails_5.0.7.gemfile
|
13
|
+
- gemfiles/rails_5.1.6.gemfile
|
14
|
+
- gemfiles/rails_5.2.0.gemfile
|
14
15
|
matrix:
|
15
16
|
include:
|
16
|
-
- rvm: 2.4.
|
17
|
-
gemfile: gemfiles/rails_4.2.
|
17
|
+
- rvm: 2.4.4
|
18
|
+
gemfile: gemfiles/rails_4.2.10.gemfile
|
18
19
|
env: DB_ADAPTER=postgresql
|
19
|
-
- rvm: 2.4.
|
20
|
-
gemfile: gemfiles/rails_5.0.
|
20
|
+
- rvm: 2.4.4
|
21
|
+
gemfile: gemfiles/rails_5.0.7.gemfile
|
21
22
|
env: DB_ADAPTER=postgresql
|
22
|
-
- rvm: 2.4.
|
23
|
-
gemfile: gemfiles/rails_5.1.
|
23
|
+
- rvm: 2.4.4
|
24
|
+
gemfile: gemfiles/rails_5.1.6.gemfile
|
24
25
|
env: DB_ADAPTER=postgresql
|
25
|
-
- rvm: 2.4.
|
26
|
-
gemfile: gemfiles/
|
26
|
+
- rvm: 2.4.4
|
27
|
+
gemfile: gemfiles/rails_5.2.0.gemfile
|
28
|
+
env: DB_ADAPTER=postgresql
|
29
|
+
- rvm: 2.4.4
|
30
|
+
gemfile: gemfiles/rails_4.2.10.gemfile
|
31
|
+
env: DB_ADAPTER=mysql2
|
32
|
+
- rvm: 2.4.4
|
33
|
+
gemfile: gemfiles/rails_5.0.7.gemfile
|
27
34
|
env: DB_ADAPTER=mysql2
|
28
|
-
- rvm: 2.4.
|
29
|
-
gemfile: gemfiles/rails_5.
|
35
|
+
- rvm: 2.4.4
|
36
|
+
gemfile: gemfiles/rails_5.1.6.gemfile
|
30
37
|
env: DB_ADAPTER=mysql2
|
31
|
-
- rvm: 2.4.
|
32
|
-
gemfile: gemfiles/rails_5.
|
38
|
+
- rvm: 2.4.4
|
39
|
+
gemfile: gemfiles/rails_5.2.0.gemfile
|
33
40
|
env: DB_ADAPTER=mysql2
|
34
|
-
- rvm: 2.4.
|
35
|
-
gemfile: gemfiles/rails_4.2.
|
41
|
+
- rvm: 2.4.4
|
42
|
+
gemfile: gemfiles/rails_4.2.10.gemfile
|
43
|
+
env: DB_ADAPTER=oracle_enhanced
|
44
|
+
- rvm: 2.4.4
|
45
|
+
gemfile: gemfiles/rails_5.0.7.gemfile
|
36
46
|
env: DB_ADAPTER=oracle_enhanced
|
37
|
-
- rvm: 2.4.
|
38
|
-
gemfile: gemfiles/rails_5.
|
47
|
+
- rvm: 2.4.4
|
48
|
+
gemfile: gemfiles/rails_5.1.6.gemfile
|
39
49
|
env: DB_ADAPTER=oracle_enhanced
|
40
|
-
- rvm: 2.4.
|
41
|
-
gemfile: gemfiles/rails_5.
|
50
|
+
- rvm: 2.4.4
|
51
|
+
gemfile: gemfiles/rails_5.2.0.gemfile
|
42
52
|
env: DB_ADAPTER=oracle_enhanced
|
43
53
|
after_success:
|
44
54
|
- bundle exec codeclimate-test-reporter
|
@@ -53,6 +63,8 @@ addons:
|
|
53
63
|
- mysql-client-core-5.6
|
54
64
|
- mysql-client-5.6
|
55
65
|
before_install:
|
66
|
+
- gem update --system
|
67
|
+
- gem install bundler
|
56
68
|
- sh -c "if [ '$DB_ADAPTER' = 'mysql2' ]; then mysql -e 'create database ajax_datatables_rails;'; fi"
|
57
69
|
- sh -c "if [ '$DB_ADAPTER' = 'postgresql' ]; then psql -c 'create database ajax_datatables_rails;' -U postgres; fi"
|
58
70
|
- sh -c "if [ '$DB_ADAPTER' = 'oracle_enhanced' ]; then ./spec/install_oracle.sh; fi"
|
data/Appraisals
CHANGED
@@ -1,33 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RAILS_VERSIONS = {
|
2
4
|
'4.0.13' => {
|
3
5
|
'mysql2' => '~> 0.3.18',
|
4
6
|
'activerecord-oracle_enhanced-adapter' => '~> 1.5.0'
|
5
7
|
},
|
6
|
-
'4.1.
|
8
|
+
'4.1.16' => {
|
7
9
|
'mysql2' => '~> 0.3.18',
|
8
10
|
'activerecord-oracle_enhanced-adapter' => '~> 1.5.0'
|
9
11
|
},
|
10
|
-
'4.2.
|
12
|
+
'4.2.10' => {
|
11
13
|
'activerecord-oracle_enhanced-adapter' => '~> 1.6.0'
|
12
14
|
},
|
13
|
-
'5.0.
|
15
|
+
'5.0.7' => {
|
14
16
|
'activerecord-oracle_enhanced-adapter' => '~> 1.7.0',
|
15
17
|
'ruby-oci8' => ''
|
16
18
|
},
|
17
|
-
'5.1.
|
19
|
+
'5.1.6' => {
|
18
20
|
'activerecord-oracle_enhanced-adapter' => '~> 1.8.0',
|
19
21
|
'ruby-oci8' => ''
|
22
|
+
},
|
23
|
+
'5.2.0' => {
|
24
|
+
'activerecord-oracle_enhanced-adapter' => '~> 5.2.0',
|
25
|
+
'ruby-oci8' => ''
|
20
26
|
}
|
21
|
-
}
|
27
|
+
}.freeze
|
22
28
|
|
23
29
|
RAILS_VERSIONS.each do |version, gems|
|
24
30
|
appraise "rails_#{version}" do
|
25
31
|
gem 'rails', version
|
26
|
-
gems.each do |name,
|
27
|
-
if
|
32
|
+
gems.each do |name, gem_version|
|
33
|
+
if gem_version.empty?
|
28
34
|
gem name
|
29
35
|
else
|
30
|
-
gem name,
|
36
|
+
gem name, gem_version
|
31
37
|
end
|
32
38
|
end
|
33
39
|
end
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,30 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
-
## 0.
|
3
|
+
## 0.4.1 (2018-05-06)
|
4
|
+
|
5
|
+
* Fix: Restore behavior of #filter method [Comment](https://github.com/jbox-web/ajax-datatables-rails/commit/07795fd26849ff1b3b567f4ce967f722907a45be#comments)
|
6
|
+
* Fix: Fix erroneous offset/start behavior [PR #264](https://github.com/jbox-web/ajax-datatables-rails/pull/264)
|
7
|
+
* Fix: "orderable" option has no effect [Issue #245](https://github.com/jbox-web/ajax-datatables-rails/issues/245)
|
8
|
+
* Fix: Fix undefined method #and [PR #235](https://github.com/jbox-web/ajax-datatables-rails/pull/235)
|
9
|
+
* Add: Add "order nulls last" option [PR #79](https://github.com/jbox-web/ajax-datatables-rails/pull/279)
|
10
|
+
* Change: Rename `additional_datas` method as `additional_data` [PR #251](https://github.com/jbox-web/ajax-datatables-rails/pull/251)
|
11
|
+
* Change: Added timezone support for daterange [PR #261](https://github.com/jbox-web/ajax-datatables-rails/pull/261)
|
12
|
+
* Change: Add # frozen_string_literal: true pragma
|
13
|
+
* Various improvements in internal API
|
14
|
+
|
15
|
+
**Note :** This is the last version to support Rails 4.0.x and Rails 4.1.x
|
16
|
+
|
17
|
+
|
18
|
+
## 0.4.0 (2017-05-21)
|
19
|
+
|
20
|
+
**Warning:** this version is a **major break** from v0.3. The core has been rewriten to remove dependency on Kaminari (or WillPaginate).
|
21
|
+
|
22
|
+
It also brings a new (more natural) way of defining columns, based on hash definitions (and not arrays) and add some filtering options for column search. Take a look at the [README](https://github.com/jbox-web/ajax-datatables-rails#customize-the-generated-datatables-class) for more infos.
|
23
|
+
|
24
|
+
## 0.3.1 (2015-07-13)
|
4
25
|
* Adds `:oracle` as supported `db_adapter`. Thanks to [lutechspa](https://github.com/lutechspa) for this contribution.
|
5
26
|
|
6
|
-
## 0.3.0
|
27
|
+
## 0.3.0 (2015-01-30)
|
7
28
|
* Changes to the `sortable_columns` and `searchable_columns` syntax as it
|
8
29
|
required us to do unnecessary guessing. New syntax is `ModelName.column_name`
|
9
30
|
or `Namespace::ModelName.column_name`. Old syntax of `table_name.column_name`
|
@@ -14,7 +35,7 @@
|
|
14
35
|
for this contribution.
|
15
36
|
* Moves paginator settings to configuration initializer.
|
16
37
|
|
17
|
-
## 0.2.1
|
38
|
+
## 0.2.1 (2014-11-26)
|
18
39
|
* Fix count method to work with select statements under Rails 4.1. Thanks to
|
19
40
|
[Jason Mitchell](https://github.com/mitchej123) for the contribution.
|
20
41
|
* Edits to `README` documentation about the `options` hash. Thanks to
|
@@ -32,22 +53,22 @@ text-based columns and perform searches depending on the use of `:mysql2`,
|
|
32
53
|
`:sqlite3` or `:pg`. Thanks to [M. Saiqul Haq](https://github.com/saiqulhaq)
|
33
54
|
for contributing this feature.
|
34
55
|
|
35
|
-
## 0.2.0
|
56
|
+
## 0.2.0 (2014-06-19)
|
36
57
|
* This version works with jQuery dataTables ver. 1.10 and it's new API syntax.
|
37
58
|
* Added `legacy` branch to repo. If your project is working with jQuery
|
38
59
|
dataTables ver. 1.9, this is the branch you need to pull, or use the last
|
39
60
|
`0.1.x` version of this gem.
|
40
61
|
|
41
|
-
## 0.1.2
|
62
|
+
## 0.1.2 (2014-06-18)
|
42
63
|
* Fixes `where` clause being built even when search term is an empty string.
|
43
64
|
Thanks to [e-fisher](https://github.com/e-fisher) for spotting and fixing this.
|
44
65
|
|
45
|
-
## 0.1.1
|
66
|
+
## 0.1.1 (2014-06-13)
|
46
67
|
* Fixes problem on `searchable_columns` where the corresponding model is
|
47
68
|
a composite model name, e.g. `UserData`, `BillingAddress`.
|
48
69
|
Thanks to [iruca3](https://github.com/iruca3) for the fix.
|
49
70
|
|
50
|
-
## 0.1.0
|
71
|
+
## 0.1.0 (2014-05-21)
|
51
72
|
* A fresh start. Sets base class name to: `AjaxDatatablesRails::Base`.
|
52
73
|
* Extracts pagination functions to mixable modules.
|
53
74
|
* A user would have the option to stick to the base
|
@@ -65,3 +86,7 @@ Thanks to [iruca3](https://github.com/iruca3) for the fix.
|
|
65
86
|
* Sets generator inside the `Rails` namespace. To generate an
|
66
87
|
`AjaxDatatablesRails` child class, just execute the
|
67
88
|
generator like this: `$ rails generate datatable NAME`.
|
89
|
+
|
90
|
+
## 0.0.1 (2012-09-10)
|
91
|
+
|
92
|
+
First release!
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,73 +8,138 @@
|
|
8
8
|
[](https://codeclimate.com/github/jbox-web/ajax-datatables-rails/coverage)
|
9
9
|
[](https://gemnasium.com/jbox-web/ajax-datatables-rails)
|
10
10
|
|
11
|
-
|
11
|
+
**Important : This gem is targeted at DataTables version 1.10.x.**
|
12
|
+
|
13
|
+
It's tested against :
|
14
|
+
|
15
|
+
* Rails 4.0.13 / 4.1.16 / 4.2.10 / 5.0.7 / 5.1.6 / 5.2.0
|
16
|
+
* Ruby 2.2.10 / 2.3.7 / 2.4.4 / 2.5.1
|
17
|
+
* Postgresql 9.6
|
18
|
+
* MySQL 5.6
|
19
|
+
* Oracle XE 11.2 (thanks to [travis-oracle](https://github.com/cbandy/travis-oracle))
|
20
|
+
* SQLite3
|
21
|
+
|
22
|
+
## Description
|
23
|
+
|
24
|
+
> [DataTables](https://datatables.net/) is a nifty jQuery plugin that adds the ability to paginate, sort, and search your html tables.
|
25
|
+
> When dealing with large tables (more than a couple of hundred rows) however, we run into performance issues.
|
26
|
+
> These can be fixed by using server-side pagination, but this breaks some DataTables functionality.
|
12
27
|
>
|
13
|
-
>
|
28
|
+
> `ajax-datatables-rails` is a wrapper around DataTables ajax methods that allow synchronization with server-side pagination in a Rails app.
|
29
|
+
> It was inspired by this [Railscast](http://railscasts.com/episodes/340-datatables).
|
30
|
+
> I needed to implement a similar solution in a couple projects I was working on, so I extracted a solution into a gem.
|
14
31
|
>
|
15
|
-
>
|
16
|
-
>
|
17
|
-
>
|
18
|
-
>
|
19
|
-
>
|
20
|
-
|
32
|
+
> Joel Quenneville (original author)
|
33
|
+
>
|
34
|
+
> I needed a good gem to manage a lot of DataTables so I chose this one :)
|
35
|
+
>
|
36
|
+
> Nicolas Rodriguez (current maintainer)
|
37
|
+
|
38
|
+
The final goal of this gem is to **generate a JSON** content that will be given to jQuery DataTables.
|
39
|
+
All the datatable customizations (header, tr, td, css classes, width, height, buttons, etc...) **must** take place in the [javascript definition](#5-wire-up-the-javascript) of the datatable.
|
40
|
+
jQuery DataTables is a very powerful tool with a lot of customizations available. Take the time to [read the doc](https://datatables.net/reference/option/).
|
21
41
|
|
22
|
-
## Description
|
23
42
|
|
24
|
-
|
25
|
-
and search your html tables. When dealing with large tables
|
26
|
-
(more than a couple hundred rows) however, we run into performance issues.
|
27
|
-
These can be fixed by using server-side pagination, but this breaks some
|
28
|
-
datatables functionality.
|
43
|
+
## Warning
|
29
44
|
|
30
|
-
|
31
|
-
synchronization with server-side pagination in a rails app. It was inspired by
|
32
|
-
this [Railscast](http://railscasts.com/episodes/340-datatables). I needed to
|
33
|
-
implement a similar solution in a couple projects I was working on, so I
|
34
|
-
extracted a solution into a gem.
|
45
|
+
**Breaking changes :** the *v0.4* version is a **major break** from *v0.3*.
|
35
46
|
|
36
|
-
|
47
|
+
The core has been rewriten to remove dependency on [Kaminari](https://github.com/kaminari/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate).
|
37
48
|
|
38
|
-
|
39
|
-
|
49
|
+
It also brings a new (more natural) way of defining columns, based on hash definitions (and not arrays) and add some filtering options for column search.
|
50
|
+
|
51
|
+
[See below](#3-customize-the-generated-datatables-class) for more infos.
|
52
|
+
|
53
|
+
To migrate on the v0.4 you'll need to :
|
54
|
+
|
55
|
+
* update your DataTables classes to remove all the `extend` directives
|
56
|
+
* switch to hash definitions of `view_columns`
|
57
|
+
* update your views to declare your columns bindings ([See here](#5-wire-up-the-javascript))
|
40
58
|
|
41
|
-
Adding support for `Sequel`, `Mongoid` and `MongoMapper` is a planned feature
|
42
|
-
for this gem. If you'd be interested in contributing to speed development,
|
43
|
-
please [open an issue](https://github.com/antillas21/ajax-datatables-rails/issues/new)
|
44
|
-
and get in touch.
|
45
59
|
|
46
60
|
## Installation
|
47
61
|
|
48
62
|
Add these lines to your application's Gemfile:
|
49
63
|
|
50
64
|
```ruby
|
51
|
-
gem 'jquery-datatables-rails'
|
52
65
|
gem 'ajax-datatables-rails'
|
53
66
|
```
|
54
67
|
|
55
68
|
And then execute:
|
56
69
|
|
57
70
|
```sh
|
58
|
-
$ bundle
|
71
|
+
$ bundle install
|
59
72
|
```
|
60
73
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
[
|
74
|
+
We assume here that you have already installed [jQuery DataTables](https://datatables.net/).
|
75
|
+
|
76
|
+
You can install jQuery DataTables :
|
77
|
+
|
78
|
+
* with the [`jquery-datatables-rails`](https://github.com/rweng/jquery-datatables-rails) gem (which is a bit outdated)
|
79
|
+
* by adding the assets manually (in `vendor/assets`)
|
80
|
+
* with [Rails webpacker gem](https://github.com/rails/webpacker) (see [here](/doc/webpack.md) for more infos)
|
81
|
+
|
82
|
+
|
83
|
+
## Configuration
|
84
|
+
|
85
|
+
Generate the `ajax-datatables-rails` config file with this command :
|
86
|
+
|
87
|
+
```sh
|
88
|
+
$ bundle exec rails generate datatable:config
|
89
|
+
```
|
90
|
+
|
91
|
+
Doing so, will create the `config/initializers/ajax_datatables_rails.rb` file with the following content :
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
AjaxDatatablesRails.configure do |config|
|
95
|
+
# available options for db_adapter are: :pg, :mysql, :mysql2, :sqlite, :sqlite3
|
96
|
+
# config.db_adapter = :pg
|
97
|
+
|
98
|
+
# Or you can use your rails environment adapter if you want a generic dev and production
|
99
|
+
# config.db_adapter = Rails.configuration.database_configuration[Rails.env]['adapter'].to_sym
|
100
|
+
|
101
|
+
# available options for orm are: :active_record, :mongoid
|
102
|
+
# config.orm = :active_record
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
Uncomment the `config.db_adapter` line and set the corresponding value to your database and gem. This is all you need.
|
107
|
+
|
108
|
+
Uncomment the `config.orm` line to set `active_record or mongoid` if included in your project. It defaults to `active_record`.
|
66
109
|
|
110
|
+
#### Note
|
67
111
|
|
68
|
-
|
112
|
+
Currently `AjaxDatatablesRails` only supports `ActiveRecord` as ORM for performing database queries.
|
69
113
|
|
70
|
-
|
71
|
-
an index page of users from a `User` model, and that we are using postgresql as
|
72
|
-
our db, because you __should be using it__, if not, please refer to the
|
73
|
-
[Searching on non text-based columns](#searching-on-non-text-based-columns)
|
74
|
-
entry in the Additional Notes section.*
|
114
|
+
Adding support for `Sequel`, `Mongoid` and `MongoMapper` is (more or less) a planned feature for this gem.
|
75
115
|
|
116
|
+
If you'd be interested in contributing to speed development, please [open an issue](https://github.com/antillas21/ajax-datatables-rails/issues/new) and get in touch.
|
76
117
|
|
77
|
-
|
118
|
+
|
119
|
+
## Quick start (in 5 steps)
|
120
|
+
|
121
|
+
The following examples assume that we are setting up `ajax-datatables-rails` for an index page of users from a `User` model,
|
122
|
+
and that we are using Postgresql as our db, because you **should be using it**. (It also works with other DB, see above, just be sure to have [configured the right adapter](#configuration))
|
123
|
+
|
124
|
+
The goal is to render a users table and display : `id`, `first name`, `last name`, `email`, and `bio` for each user.
|
125
|
+
|
126
|
+
Something like this:
|
127
|
+
|
128
|
+
|ID |First Name|Last Name|Email |Brief Bio|
|
129
|
+
|---|----------|---------|----------------------|---------|
|
130
|
+
| 1 |John |Doe |john.doe@example.net |Is your default user everywhere|
|
131
|
+
| 2 |Jane |Doe |jane.doe@example.net |Is John's wife|
|
132
|
+
| 3 |James |Doe |james.doe@example.net |Is John's brother and best friend|
|
133
|
+
|
134
|
+
Here the steps we're going through :
|
135
|
+
|
136
|
+
1. [Generate the datatable class](#1-generate-the-datatable-class)
|
137
|
+
2. [Build the View](#2-build-the-view)
|
138
|
+
3. [Customize the generated Datatables class](#3-customize-the-generated-datatables-class)
|
139
|
+
4. [Setup the Controller action](#4-setup-the-controller-action)
|
140
|
+
5. [Wire up the Javascript](#5-wire-up-the-javascript)
|
141
|
+
|
142
|
+
### 1) Generate the datatable class
|
78
143
|
|
79
144
|
Run the following command:
|
80
145
|
|
@@ -88,31 +153,24 @@ Open the file and customize in the functions as directed by the comments.
|
|
88
153
|
Take a look [here](#generator-syntax) for an explanation about the generator syntax.
|
89
154
|
|
90
155
|
|
91
|
-
### Build the View
|
92
|
-
|
93
|
-
You should always start by the single source of truth, which is your html view. Suppose we need to render a users table and display: first name, last name, and bio for each user.
|
94
|
-
|
95
|
-
Something like this:
|
96
|
-
|
97
|
-
|First Name|Last Name|Brief Bio|
|
98
|
-
|----------|---------|---------|
|
99
|
-
|John |Doe |Is your default user everywhere|
|
100
|
-
|Jane |Doe |Is John's wife|
|
101
|
-
|James |Doe |Is John's brother and best friend|
|
156
|
+
### 2) Build the View
|
102
157
|
|
158
|
+
You should always start by the single source of truth, which is your html view.
|
103
159
|
|
104
160
|
* Set up an html `<table>` with a `<thead>` and `<tbody>`
|
105
161
|
* Add in your table headers if desired
|
106
|
-
* Don't add any rows to the body of the table,
|
162
|
+
* Don't add any rows to the body of the table, DataTables does this automatically
|
107
163
|
* Add a data attribute to the `<table>` tag with the url of the JSON feed, in our case is the `users_path` as we're pointing to the `UsersController#index` action
|
108
164
|
|
109
165
|
|
110
166
|
```html
|
111
|
-
<table id="users-
|
167
|
+
<table id="users-datatable" data-source="<%= users_path(format: :json) %>">
|
112
168
|
<thead>
|
113
169
|
<tr>
|
170
|
+
<th>ID</th>
|
114
171
|
<th>First Name</th>
|
115
172
|
<th>Last Name</th>
|
173
|
+
<th>Email</th>
|
116
174
|
<th>Brief Bio</th>
|
117
175
|
</tr>
|
118
176
|
</thead>
|
@@ -122,25 +180,22 @@ Something like this:
|
|
122
180
|
```
|
123
181
|
|
124
182
|
|
125
|
-
### Customize the generated Datatables class
|
183
|
+
### 3) Customize the generated Datatables class
|
126
184
|
|
127
|
-
|
128
|
-
def view_columns
|
129
|
-
# Declare strings in this format: ModelName.column_name
|
130
|
-
# or in aliased_join_table.column_name format
|
131
|
-
@view_columns ||= {}
|
132
|
-
end
|
133
|
-
```
|
185
|
+
#### a. Declare columns mapping
|
134
186
|
|
135
|
-
|
187
|
+
First we need to declare in `view_columns` the list of the model(s) columns mapped to the data we need to present.
|
188
|
+
In this case: `id`, `first_name`, `last_name`, `email` and `bio`.
|
136
189
|
|
137
190
|
This gives us:
|
138
191
|
|
139
192
|
```ruby
|
140
193
|
def view_columns
|
141
194
|
@view_columns ||= {
|
195
|
+
id: { source: "User.id" },
|
142
196
|
first_name: { source: "User.first_name", cond: :like, searchable: true, orderable: true },
|
143
197
|
last_name: { source: "User.last_name", cond: :like },
|
198
|
+
email: { source: "User.email" },
|
144
199
|
bio: { source: "User.bio" },
|
145
200
|
}
|
146
201
|
end
|
@@ -152,52 +207,32 @@ end
|
|
152
207
|
|
153
208
|
* `:like`, `:start_with`, `:end_with` for string or full text search
|
154
209
|
* `:eq`, `:not_eq`, `:lt`, `:gt`, `:lteq`, `:gteq`, `:in` for numeric
|
155
|
-
* `:date_range` for date range (only for Rails > 4.2.x)
|
210
|
+
* `:date_range` for date range (only for Rails > 4.2.x, see [here](#daterange-search))
|
156
211
|
* `:null_value` for nil field
|
157
|
-
* `Proc` for whatever
|
212
|
+
* `Proc` for whatever (see [here](https://github.com/ajahongir/ajax-datatables-rails-v-0-4-0-how-to/blob/master/app/datatables/city_datatable.rb) for real example)
|
158
213
|
|
159
|
-
|
160
|
-
[Read these notes](#columns-syntax) about considerations for the `view_columns` method.
|
214
|
+
See [here](#columns-syntax) to get more details about columns definitions and how to play with associated models.
|
161
215
|
|
216
|
+
#### b. Map data
|
162
217
|
|
163
|
-
|
164
|
-
|
165
|
-
```ruby
|
166
|
-
def data
|
167
|
-
records.map do |record|
|
168
|
-
{
|
169
|
-
# a hash of key value pairs
|
170
|
-
}
|
171
|
-
end
|
172
|
-
end
|
173
|
-
```
|
218
|
+
Then we need to map the records retrieved by the `get_raw_records` method to the real values we want to display :
|
174
219
|
|
175
220
|
```ruby
|
176
221
|
def data
|
177
222
|
records.map do |record|
|
178
223
|
{
|
224
|
+
id: record.id,
|
179
225
|
first_name: record.first_name,
|
180
226
|
last_name: record.last_name,
|
227
|
+
email: record.email,
|
181
228
|
bio: record.bio,
|
182
|
-
|
229
|
+
DT_RowId: record.id, # This will set the id attribute on the corresponding <tr> in the datatable
|
183
230
|
}
|
184
231
|
end
|
185
232
|
end
|
186
233
|
```
|
187
|
-
|
188
234
|
You can either use the v0.3 Array style for your columns :
|
189
235
|
|
190
|
-
```ruby
|
191
|
-
def data
|
192
|
-
records.map do |record|
|
193
|
-
[
|
194
|
-
# comma separated list of the values for each cell of a table row
|
195
|
-
# example: record.first_name, record.last_name
|
196
|
-
]
|
197
|
-
end
|
198
|
-
end
|
199
|
-
```
|
200
|
-
|
201
236
|
This method builds a 2d array that is used by datatables to construct the html
|
202
237
|
table. Insert the values you want on each column.
|
203
238
|
|
@@ -205,34 +240,27 @@ table. Insert the values you want on each column.
|
|
205
240
|
def data
|
206
241
|
records.map do |record|
|
207
242
|
[
|
243
|
+
record.id,
|
208
244
|
record.first_name,
|
209
245
|
record.last_name,
|
246
|
+
record.email,
|
210
247
|
record.bio
|
211
248
|
]
|
212
249
|
end
|
213
250
|
end
|
214
251
|
```
|
215
252
|
|
216
|
-
|
253
|
+
The drawback of this method is that you can't pass the `DT_RowId` so it's tricky to set the id attribute on the corresponding `<tr>` in the datatable (need to be done on JS side).
|
217
254
|
|
255
|
+
[See here](#using-view-helpers) if you need to use view helpers like `link_to`, `mail_to`, etc...
|
218
256
|
|
219
|
-
#### Get Raw Records
|
220
|
-
|
221
|
-
```ruby
|
222
|
-
def get_raw_records
|
223
|
-
# insert query here
|
224
|
-
end
|
225
|
-
```
|
257
|
+
#### c. Get Raw Records
|
226
258
|
|
227
259
|
This is where your query goes.
|
228
260
|
|
229
261
|
```ruby
|
230
262
|
def get_raw_records
|
231
|
-
# suppose we need all User records
|
232
|
-
# Rails 4+
|
233
263
|
User.all
|
234
|
-
# Rails 3.x
|
235
|
-
# User.scoped
|
236
264
|
end
|
237
265
|
```
|
238
266
|
|
@@ -246,105 +274,17 @@ def get_raw_records
|
|
246
274
|
end
|
247
275
|
```
|
248
276
|
|
249
|
-
You can put any logic in `get_raw_records` [based on any parameters you inject](#options) in the `Datatable` object.
|
250
|
-
|
251
|
-
> __IMPORTANT:__ Make sure to return an `ActiveRecord::Relation` object
|
252
|
-
> as the end product of this method.
|
253
|
-
>
|
254
|
-
> Why? Because the result from this method, will be chained (for now)
|
255
|
-
> to `ActiveRecord` methods for sorting, filtering and pagination.
|
256
|
-
|
277
|
+
You can put any logic in `get_raw_records` [based on any parameters you inject](#pass-options-to-the-datatable-class) in the `Datatable` object.
|
257
278
|
|
258
|
-
|
279
|
+
**IMPORTANT :** Because the result of this method will be chained to `ActiveRecord` methods for sorting, filtering and pagination,
|
280
|
+
make sure to return an `ActiveRecord::Relation` object.
|
259
281
|
|
260
|
-
|
261
|
-
some associated nested models and in a report you want to show fields from
|
262
|
-
these tables.
|
282
|
+
#### d. Additional data
|
263
283
|
|
264
|
-
|
265
|
-
Contact, Competency and CompetencyType` models. We want to have a datatables
|
266
|
-
report which has the following column:
|
284
|
+
You can inject other key/value pairs in the rendered JSON by defining the `#additional_data` method :
|
267
285
|
|
268
286
|
```ruby
|
269
|
-
|
270
|
-
'courses.name',
|
271
|
-
'events.title',
|
272
|
-
'events.event_start',
|
273
|
-
'events.event_end',
|
274
|
-
'contacts.full_name',
|
275
|
-
'competency_types.name',
|
276
|
-
'events.status'
|
277
|
-
```
|
278
|
-
|
279
|
-
We want to sort and search on all columns of the list. The related definition
|
280
|
-
would be:
|
281
|
-
|
282
|
-
```ruby
|
283
|
-
def view_columns
|
284
|
-
@view_columns ||= [
|
285
|
-
'Coursetype.name',
|
286
|
-
'Course.name',
|
287
|
-
'Event.title',
|
288
|
-
'Event.event_start',
|
289
|
-
'Event.event_end',
|
290
|
-
'Contact.last_name',
|
291
|
-
'CompetencyType.name',
|
292
|
-
'Event.status'
|
293
|
-
]
|
294
|
-
end
|
295
|
-
|
296
|
-
def get_raw_records
|
297
|
-
Event.joins(
|
298
|
-
{ course: :coursetype },
|
299
|
-
{ allocations: {
|
300
|
-
teacher: [:contact, {competencies: :competency_type}]
|
301
|
-
}
|
302
|
-
}).distinct
|
303
|
-
end
|
304
|
-
```
|
305
|
-
|
306
|
-
__Some comments for the above code:__
|
307
|
-
|
308
|
-
1. In the `get_raw_records` method we have quite a complex query having one to
|
309
|
-
many and may to many associations using the joins ActiveRecord method.
|
310
|
-
The joins will generate INNER JOIN relations in the SQL query. In this case,
|
311
|
-
we do not include all event in the report if we have events which is not
|
312
|
-
associated with any model record from the relation.
|
313
|
-
|
314
|
-
2. To have all event records in the list we should use the `.includes` method,
|
315
|
-
which generate LEFT OUTER JOIN relation of the SQL query.
|
316
|
-
__IMPORTANT:__ Make sure to append `.references(:related_model)` with any
|
317
|
-
associated model. That forces the eager loading of all the associated models
|
318
|
-
by one SQL query, and the search condition for any column works fine.
|
319
|
-
Otherwise the `:recordsFiltered => filter_records(get_raw_records).count(:all)`
|
320
|
-
will generate 2 SQL queries (one for the Event model, and then another for the
|
321
|
-
associated tables). The `:recordsFiltered => filter_records(get_raw_records).count(:all)`
|
322
|
-
will use only the first one to return from the ActiveRecord::Relation object
|
323
|
-
in `get_raw_records` and you will get an error message of __Unknown column
|
324
|
-
'yourtable.yourfield' in 'where clause'__ in case the search field value
|
325
|
-
is not empty.
|
326
|
-
|
327
|
-
So the query using the `.includes()` method is:
|
328
|
-
|
329
|
-
```ruby
|
330
|
-
def get_raw_records
|
331
|
-
Event.includes(
|
332
|
-
{ course: :coursetype },
|
333
|
-
{ allocations: {
|
334
|
-
teacher: [:contact, { competencies: :competency_type }]
|
335
|
-
}
|
336
|
-
}
|
337
|
-
).references(:course).distinct
|
338
|
-
end
|
339
|
-
```
|
340
|
-
|
341
|
-
|
342
|
-
#### Additional datas
|
343
|
-
|
344
|
-
You can inject other key/value pairs in the rendered JSON by defining the `#additional_datas` method :
|
345
|
-
|
346
|
-
```ruby
|
347
|
-
def additional_datas
|
287
|
+
def additional_data
|
348
288
|
{
|
349
289
|
foo: 'bar'
|
350
290
|
}
|
@@ -354,7 +294,7 @@ end
|
|
354
294
|
Very useful with https://github.com/vedmack/yadcf to provide values for dropdown filters.
|
355
295
|
|
356
296
|
|
357
|
-
### Setup the Controller action
|
297
|
+
### 4) Setup the Controller action
|
358
298
|
|
359
299
|
Set the controller to respond to JSON
|
360
300
|
|
@@ -369,9 +309,9 @@ end
|
|
369
309
|
|
370
310
|
Don't forget to make sure the proper route has been added to `config/routes.rb`.
|
371
311
|
|
372
|
-
[See here](#options) to inject params in the `UserDatatable`.
|
312
|
+
[See here](#pass-options-to-the-datatable-class) if you need to inject params in the `UserDatatable`.
|
373
313
|
|
374
|
-
### Wire up the Javascript
|
314
|
+
### 5) Wire up the Javascript
|
375
315
|
|
376
316
|
Finally, the javascript to tie this all together. In the appropriate `coffee` file:
|
377
317
|
|
@@ -379,217 +319,307 @@ Finally, the javascript to tie this all together. In the appropriate `coffee` fi
|
|
379
319
|
# users.coffee
|
380
320
|
|
381
321
|
$ ->
|
382
|
-
$('#users-
|
322
|
+
$('#users-datatable').dataTable
|
383
323
|
processing: true
|
384
324
|
serverSide: true
|
385
|
-
ajax: $('#users-
|
325
|
+
ajax: $('#users-datatable').data('source')
|
386
326
|
pagingType: 'full_numbers'
|
387
|
-
|
327
|
+
columns: [
|
328
|
+
{data: 'id'}
|
329
|
+
{data: 'first_name'}
|
330
|
+
{data: 'last_name'}
|
331
|
+
{data: 'email'}
|
332
|
+
{data: 'bio'}
|
333
|
+
]
|
334
|
+
# pagingType is optional, if you want full pagination controls.
|
388
335
|
# Check dataTables documentation to learn more about
|
389
336
|
# available options.
|
390
337
|
```
|
391
338
|
|
392
339
|
or, if you're using plain javascript:
|
340
|
+
|
393
341
|
```javascript
|
394
342
|
// users.js
|
395
343
|
|
396
344
|
jQuery(document).ready(function() {
|
397
|
-
$('#users-
|
345
|
+
$('#users-datatable').dataTable({
|
398
346
|
"processing": true,
|
399
347
|
"serverSide": true,
|
400
|
-
"ajax": $('#users-
|
348
|
+
"ajax": $('#users-datatable').data('source'),
|
401
349
|
"pagingType": "full_numbers",
|
402
|
-
|
350
|
+
"columns": [
|
351
|
+
{"data": "id"},
|
352
|
+
{"data": "first_name"},
|
353
|
+
{"data": "last_name"},
|
354
|
+
{"data": "email"},
|
355
|
+
{"data": "bio"}
|
356
|
+
]
|
357
|
+
// pagingType is optional, if you want full pagination controls.
|
403
358
|
// Check dataTables documentation to learn more about
|
404
359
|
// available options.
|
405
360
|
});
|
406
361
|
});
|
407
362
|
```
|
408
363
|
|
364
|
+
## Advanced usage
|
409
365
|
|
410
|
-
###
|
411
|
-
|
412
|
-
#### Columns syntax
|
366
|
+
### Using view helpers
|
413
367
|
|
414
|
-
|
415
|
-
the
|
368
|
+
Sometimes you'll need to use view helper methods like `link_to`, `mail_to`,
|
369
|
+
`edit_user_path`, `check_box_tag` and so on in the returned JSON representation returned by the [`data`](#b-map-data) method.
|
416
370
|
|
417
|
-
|
418
|
-
`Purchase::LineItem` and we need to have several columns from those models
|
419
|
-
available in our datatable to search and sort by.
|
371
|
+
To have these methods available to be used, this is the way to go:
|
420
372
|
|
421
373
|
```ruby
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
'PurchaseOrder.number',
|
429
|
-
'PurchaseOrder.created_at',
|
430
|
-
'Purchase::LineItem.quantity',
|
431
|
-
'Purchase::LineItem.unit_price',
|
432
|
-
'Purchase::LineItem.item_total'
|
433
|
-
]
|
434
|
-
end
|
435
|
-
```
|
436
|
-
|
374
|
+
class MyCustomDatatable < AjaxDatatablesRails::Base
|
375
|
+
# either define them one-by-one
|
376
|
+
def_delegator :@view, :check_box_tag
|
377
|
+
def_delegator :@view, :link_to
|
378
|
+
def_delegator :@view, :mail_to
|
379
|
+
def_delegator :@view, :edit_user_path
|
437
380
|
|
438
|
-
|
381
|
+
# or define them in one pass
|
382
|
+
def_delegators :@view, :check_box_tag, :link_to, :mail_to, :edit_user_path
|
439
383
|
|
440
|
-
|
384
|
+
# ... other methods (view_columns, get_raw_records...)
|
441
385
|
|
442
|
-
|
443
|
-
|
444
|
-
|
386
|
+
# now, you'll have these methods available to be used anywhere
|
387
|
+
def data
|
388
|
+
records.map do |record|
|
389
|
+
{
|
390
|
+
id: check_box_tag('users[]', record.id),
|
391
|
+
first_name: link_to(record.first_name, edit_user_path(record)),
|
392
|
+
last_name: record.last_name,
|
393
|
+
email: mail_to(record.email),
|
394
|
+
bio: record.bio
|
395
|
+
DT_RowId: record.id,
|
396
|
+
}
|
397
|
+
end
|
445
398
|
end
|
446
399
|
end
|
447
400
|
```
|
448
401
|
|
449
|
-
|
402
|
+
If you want to keep things tidy in the data mapping method, you could use
|
403
|
+
[Draper](https://github.com/drapergem/draper) to define column mappings like below.
|
404
|
+
|
405
|
+
Example :
|
450
406
|
|
451
407
|
```ruby
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
408
|
+
...
|
409
|
+
def data
|
410
|
+
records.map do |record|
|
411
|
+
{
|
412
|
+
id: record.decorate.check_box,
|
413
|
+
first_name: record.decorate.link_to,
|
414
|
+
last_name: record.decorate.last_name
|
415
|
+
email: record.decorate.email,
|
416
|
+
bio: record.decorate.bio
|
417
|
+
DT_RowId: record.id,
|
418
|
+
}
|
419
|
+
end
|
420
|
+
end
|
421
|
+
...
|
464
422
|
|
465
|
-
|
423
|
+
class UserDecorator < ApplicationDecorator
|
424
|
+
delegate :last_name, :bio
|
466
425
|
|
426
|
+
def check_box
|
427
|
+
h.check_box_tag 'users[]', object.id
|
428
|
+
end
|
467
429
|
|
468
|
-
|
430
|
+
def link_to
|
431
|
+
h.link_to object.first_name, h.edit_user_path(object)
|
432
|
+
end
|
469
433
|
|
470
|
-
|
471
|
-
|
472
|
-
|
434
|
+
def email
|
435
|
+
h.mail_to object.email
|
436
|
+
end
|
473
437
|
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
438
|
+
# Just an example of a complex method you can add to you decorator
|
439
|
+
# To render it in a datatable just add a column 'dt_actions' in
|
440
|
+
# 'view_columns' and 'data' methods and call record.decorate.dt_actions
|
441
|
+
def dt_actions
|
442
|
+
links = []
|
443
|
+
links << h.link_to 'Edit', h.edit_user_path(object) if h.policy(object).update?
|
444
|
+
links << h.link_to 'Delete', h.user_path(object), method: :delete, remote: true if h.policy(object).destroy?
|
445
|
+
h.safe_join(links, '')
|
446
|
+
end
|
447
|
+
end
|
448
|
+
```
|
479
449
|
|
480
|
-
|
481
|
-
`postgresql`), your database will complain that it does not understand the
|
482
|
-
default typecast used to enable such searches.
|
450
|
+
**Note :** On the long term it's much more cleaner than using `def_delegator` since decorators are reusable everywhere in your application :)
|
483
451
|
|
452
|
+
So we **strongly recommand you to use Draper decorators.** It will help keeping your DataTables class small and clean and keep focused on what they should do (mostly) : filtering records ;)
|
484
453
|
|
485
|
-
|
454
|
+
**Note 2 :** The `def_delegator` might disappear in a near future : [#288 [RFC] Remove dependency on view_context](https://github.com/jbox-web/ajax-datatables-rails/issues/288).
|
455
|
+
You're invited to give your opinion :)
|
486
456
|
|
487
|
-
|
457
|
+
### Pass options to the datatable class
|
488
458
|
|
489
|
-
|
490
|
-
* create the file from scratch.
|
459
|
+
An `AjaxDatatablesRails::Base` inherited class can accept an options hash at initialization. This provides room for flexibility when required.
|
491
460
|
|
492
|
-
|
461
|
+
Example:
|
493
462
|
|
494
|
-
```
|
495
|
-
|
496
|
-
|
463
|
+
```ruby
|
464
|
+
# In the controller
|
465
|
+
def index
|
466
|
+
respond_to do |format|
|
467
|
+
format.html
|
468
|
+
format.json { render json: UserDatatable.new(view_context, user: current_user, from: 1.month.ago) }
|
469
|
+
end
|
470
|
+
end
|
497
471
|
|
498
|
-
|
499
|
-
|
472
|
+
# The datatable class
|
473
|
+
class UnrespondedMessagesDatatable < AjaxDatatablesRails::Base
|
500
474
|
|
501
|
-
|
502
|
-
AjaxDatatablesRails.configure do |config|
|
503
|
-
# available options for db_adapter are: :pg, :mysql, :mysql2, :sqlite, :sqlite3
|
504
|
-
# config.db_adapter = :pg
|
475
|
+
# ... other methods (view_columns, data...)
|
505
476
|
|
506
|
-
|
507
|
-
|
508
|
-
end
|
509
|
-
```
|
477
|
+
def user
|
478
|
+
@user ||= options[:user]
|
479
|
+
end
|
510
480
|
|
511
|
-
|
512
|
-
|
481
|
+
def from
|
482
|
+
@from ||= options[:from].beginning_of_day
|
483
|
+
end
|
513
484
|
|
514
|
-
|
515
|
-
|
485
|
+
def to
|
486
|
+
@to ||= Date.today.end_of_day
|
487
|
+
end
|
516
488
|
|
517
|
-
|
518
|
-
|
489
|
+
# We can now customize the get_raw_records method
|
490
|
+
# with the options we've injected
|
491
|
+
def get_raw_records
|
492
|
+
user.messages.unresponded.where(received_at: from..to)
|
493
|
+
end
|
519
494
|
|
495
|
+
end
|
496
|
+
```
|
520
497
|
|
521
|
-
|
498
|
+
### Columns syntax
|
522
499
|
|
523
|
-
|
524
|
-
`edit_resource_path` in the returned JSON representation returned by the `data`
|
525
|
-
method.
|
500
|
+
You can mix several model in the same datatable.
|
526
501
|
|
527
|
-
|
502
|
+
Suppose we have the following models: `User`, `PurchaseOrder`,
|
503
|
+
`Purchase::LineItem` and we need to have several columns from those models
|
504
|
+
available in our datatable to search and sort by.
|
528
505
|
|
529
506
|
```ruby
|
530
|
-
|
531
|
-
# either define them one-by-one
|
532
|
-
def_delegator :@view, :link_to
|
533
|
-
def_delegator :@view, :h
|
534
|
-
def_delegator :@view, :mail_to
|
535
|
-
|
536
|
-
# or define them in one pass
|
537
|
-
def_delegators :@view, :link_to, :h, :mailto, :edit_resource_path, :other_method
|
507
|
+
# we use the ModelName.column_name notation to declare our columns
|
538
508
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
end
|
509
|
+
def view_columns
|
510
|
+
@view_columns ||= {
|
511
|
+
first_name: 'User.first_name',
|
512
|
+
last_name: 'User.last_name',
|
513
|
+
order_number: 'PurchaseOrder.number',
|
514
|
+
order_created_at: 'PurchaseOrder.created_at',
|
515
|
+
quantity: 'Purchase::LineItem.quantity',
|
516
|
+
unit_price: 'Purchase::LineItem.unit_price',
|
517
|
+
item_total: 'Purchase::LineItem.item_total'
|
518
|
+
}
|
550
519
|
end
|
551
520
|
```
|
552
521
|
|
522
|
+
### Associated and nested models
|
553
523
|
|
554
|
-
|
524
|
+
The previous example has only one single model. But what about if you have
|
525
|
+
some associated nested models and in a report you want to show fields from
|
526
|
+
these tables.
|
555
527
|
|
556
|
-
|
557
|
-
|
528
|
+
Take an example that has an `Event, Course, CourseType, Allocation, Teacher,
|
529
|
+
Contact, Competency and CompetencyType` models. We want to have a datatables
|
530
|
+
report which has the following column:
|
558
531
|
|
559
532
|
```ruby
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
533
|
+
'course_types.name'
|
534
|
+
'courses.name'
|
535
|
+
'contacts.full_name'
|
536
|
+
'competency_types.name'
|
537
|
+
'events.title'
|
538
|
+
'events.event_start'
|
539
|
+
'events.event_end'
|
540
|
+
'events.status'
|
567
541
|
```
|
568
542
|
|
569
|
-
|
570
|
-
|
543
|
+
We want to sort and search on all columns of the list.
|
544
|
+
The related definition would be :
|
571
545
|
|
572
546
|
```ruby
|
573
|
-
|
574
|
-
|
575
|
-
|
547
|
+
def view_columns
|
548
|
+
@view_columns ||= {
|
549
|
+
course_type: 'CourseType.name',
|
550
|
+
course_name: 'Course.name',
|
551
|
+
contact_name: 'Contact.full_name',
|
552
|
+
competency_type: 'CompetencyType.name',
|
553
|
+
event_title: 'Event.title',
|
554
|
+
event_start: 'Event.event_start',
|
555
|
+
event_end: 'Event.event_end',
|
556
|
+
event_status: 'Event.status',
|
557
|
+
}
|
576
558
|
end
|
577
559
|
|
578
|
-
def
|
579
|
-
|
560
|
+
def get_raw_records
|
561
|
+
Event.joins(
|
562
|
+
{ course: :course_type },
|
563
|
+
{ allocations: {
|
564
|
+
teacher: [:contact, { competencies: :competency_type }]
|
565
|
+
}
|
566
|
+
}).distinct
|
580
567
|
end
|
568
|
+
```
|
581
569
|
|
582
|
-
|
583
|
-
|
584
|
-
|
570
|
+
**Some comments for the above code :**
|
571
|
+
|
572
|
+
1. In the `get_raw_records` method we have quite a complex query having one to
|
573
|
+
many and many to many associations using the joins ActiveRecord method.
|
574
|
+
The joins will generate INNER JOIN relations in the SQL query. In this case,
|
575
|
+
we do not include all event in the report if we have events which is not
|
576
|
+
associated with any model record from the relation.
|
577
|
+
|
578
|
+
2. To have all event records in the list we should use the `.includes` method,
|
579
|
+
which generate LEFT OUTER JOIN relation of the SQL query.
|
585
580
|
|
581
|
+
**IMPORTANT :**
|
582
|
+
|
583
|
+
Make sure to append `.references(:related_model)` with any
|
584
|
+
associated model. That forces the eager loading of all the associated models
|
585
|
+
by one SQL query, and the search condition for any column works fine.
|
586
|
+
Otherwise the `:recordsFiltered => filter_records(get_raw_records).count(:all)`
|
587
|
+
will generate 2 SQL queries (one for the Event model, and then another for the
|
588
|
+
associated tables). The `:recordsFiltered => filter_records(get_raw_records).count(:all)`
|
589
|
+
will use only the first one to return from the ActiveRecord::Relation object
|
590
|
+
in `get_raw_records` and you will get an error message of **Unknown column
|
591
|
+
'yourtable.yourfield' in 'where clause'** in case the search field value
|
592
|
+
is not empty.
|
593
|
+
|
594
|
+
So the query using the `.includes()` method is:
|
595
|
+
|
596
|
+
```ruby
|
586
597
|
def get_raw_records
|
587
|
-
|
598
|
+
Event.includes(
|
599
|
+
{ course: :course_type },
|
600
|
+
{ allocations: {
|
601
|
+
teacher: [:contact, { competencies: :competency_type }]
|
602
|
+
}
|
603
|
+
}).references(:course).distinct
|
588
604
|
end
|
589
605
|
```
|
590
606
|
|
607
|
+
### Default scope
|
608
|
+
|
609
|
+
See [DefaultScope is evil](https://rails-bestpractices.com/posts/2013/06/15/default_scope-is-evil/) and [#223](https://github.com/jbox-web/ajax-datatables-rails/issues/223) and [#233](https://github.com/jbox-web/ajax-datatables-rails/issues/233).
|
610
|
+
|
611
|
+
### DateRange search
|
612
|
+
|
613
|
+
This feature works with [yadcf](https://github.com/vedmack/yadcf).
|
591
614
|
|
592
|
-
|
615
|
+
To enable the date range search, for example `created_at` :
|
616
|
+
|
617
|
+
* add a 'created_at' `<th>` in your html
|
618
|
+
* declare your column in `view_columns` : `created_at: { source: 'Post.created_at', cond: :date_range, delimiter: '-yadcf_delim-' }`
|
619
|
+
* add it in `data` : `created_at: record.decorate.created_at`
|
620
|
+
* setup yadcf to make `created_at` search field a range
|
621
|
+
|
622
|
+
### Generator Syntax
|
593
623
|
|
594
624
|
Also, a class that inherits from `AjaxDatatablesRails::Base` is not tied to an
|
595
625
|
existing model, module, constant or any type of class in your Rails app.
|
@@ -611,19 +641,54 @@ In the end, it's up to the developer which model(s), scope(s), relationship(s)
|
|
611
641
|
(or else) to employ inside the datatable class to retrieve records from the
|
612
642
|
database.
|
613
643
|
|
644
|
+
### Creating indices for Postgresql
|
614
645
|
|
615
|
-
|
646
|
+
In order to speed up the `ILIKE` queries that are executed when using the default configuration, you might want to consider adding some indices.
|
647
|
+
For postgresql, you are advised to use the [gin/gist index type](http://www.postgresql.org/docs/current/interactive/pgtrgm.html).
|
648
|
+
This makes it necessary to enable the postgrsql extension `pg_trgm`. Double check that you have this extension installed before trying to enable it.
|
649
|
+
A migration for enabling the extension and creating the indices could look like this:
|
616
650
|
|
617
|
-
|
651
|
+
```ruby
|
652
|
+
def change
|
653
|
+
enable_extension :pg_trgm
|
654
|
+
TEXT_SEARCH_ATTRIBUTES = ['your', 'attributes']
|
655
|
+
TABLE = 'your_table'
|
656
|
+
|
657
|
+
TEXT_SEARCH_ATTRIBUTES.each do |attr|
|
658
|
+
reversible do |dir|
|
659
|
+
dir.up do
|
660
|
+
execute "CREATE INDEX #{TABLE}_#{attr}_gin ON #{TABLE} USING gin(#{attr} gin_trgm_ops)"
|
661
|
+
end
|
662
|
+
|
663
|
+
dir.down do
|
664
|
+
remove_index TABLE.to_sym, name: "#{TABLE}_#{attr}_gin"
|
665
|
+
end
|
666
|
+
end
|
667
|
+
end
|
668
|
+
end
|
669
|
+
```
|
618
670
|
|
619
|
-
|
671
|
+
### Speedup JSON rendering
|
620
672
|
|
621
|
-
[
|
673
|
+
Install [yajl-ruby](https://github.com/brianmario/yajl-ruby), basically :
|
622
674
|
|
623
|
-
|
675
|
+
```ruby
|
676
|
+
gem 'yajl-ruby', require: 'yajl'
|
677
|
+
```
|
678
|
+
|
679
|
+
then
|
680
|
+
|
681
|
+
```sh
|
682
|
+
$ bundle install
|
683
|
+
```
|
684
|
+
|
685
|
+
That's all :) ([Automatically prefer Yajl or JSON backend over Yaml, if available](https://github.com/rails/rails/commit/63bb955a99eb46e257655c93dd64e86ebbf05651))
|
686
|
+
|
687
|
+
## Tutorial
|
624
688
|
|
625
|
-
|
689
|
+
You'll find a sample project [here](https://github.com/ajahongir/ajax-datatables-rails-v-0-4-0-how-to). Its real world example.
|
626
690
|
|
691
|
+
Filtering by JSONB column values : [#277](https://github.com/jbox-web/ajax-datatables-rails/issues/277)
|
627
692
|
|
628
693
|
## Contributing
|
629
694
|
|