datatables-net 0.4.0
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 +7 -0
- data/CHANGELOG.md +73 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +618 -0
- data/Rakefile +14 -0
- data/lib/ajax-datatables-rails.rb +11 -0
- data/lib/ajax-datatables-rails/base.rb +205 -0
- data/lib/ajax-datatables-rails/config.rb +24 -0
- data/lib/ajax-datatables-rails/datatable/column.rb +106 -0
- data/lib/ajax-datatables-rails/datatable/datatable.rb +69 -0
- data/lib/ajax-datatables-rails/datatable/simple_order.rb +31 -0
- data/lib/ajax-datatables-rails/datatable/simple_search.rb +19 -0
- data/lib/ajax-datatables-rails/orm/active_record.rb +52 -0
- data/lib/ajax-datatables-rails/version.rb +3 -0
- data/lib/generators/datatable/config_generator.rb +17 -0
- data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +7 -0
- data/lib/generators/rails/datatable_generator.rb +27 -0
- data/lib/generators/rails/templates/datatable.rb +41 -0
- data/spec/ajax-datatables-rails/base_spec.rb +140 -0
- data/spec/ajax-datatables-rails/configuration_spec.rb +43 -0
- data/spec/ajax-datatables-rails/datatable/column_spec.rb +65 -0
- data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +97 -0
- data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +12 -0
- data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +16 -0
- data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +154 -0
- data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +51 -0
- data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +42 -0
- data/spec/ajax-datatables-rails/orm/active_record_spec.rb +34 -0
- data/spec/schema.rb +43 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/test_helpers.rb +66 -0
- data/spec/test_models.rb +20 -0
- metadata +202 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module AjaxDatatablesRails
|
2
|
+
module Datatable
|
3
|
+
class SimpleSearch
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize options
|
7
|
+
@options = options || {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def value
|
11
|
+
options[:value]
|
12
|
+
end
|
13
|
+
|
14
|
+
def regexp?
|
15
|
+
options[:regex] == TRUE_VALUE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module AjaxDatatablesRails
|
2
|
+
module ORM
|
3
|
+
module ActiveRecord
|
4
|
+
|
5
|
+
def fetch_records
|
6
|
+
get_raw_records
|
7
|
+
end
|
8
|
+
|
9
|
+
def filter_records records
|
10
|
+
records.where(build_conditions)
|
11
|
+
end
|
12
|
+
|
13
|
+
def sort_records records
|
14
|
+
sort_by = datatable.orders.inject([]) do |queries, order|
|
15
|
+
column = order.column
|
16
|
+
queries << order.query(column.sort_query) if column
|
17
|
+
end
|
18
|
+
records.order(sort_by.join(", "))
|
19
|
+
end
|
20
|
+
|
21
|
+
def paginate_records records
|
22
|
+
records.offset(datatable.offset).limit(datatable.per_page)
|
23
|
+
end
|
24
|
+
|
25
|
+
# ----------------- SEARCH HELPER METHODS --------------------
|
26
|
+
|
27
|
+
def build_conditions
|
28
|
+
if datatable.searchable?
|
29
|
+
build_conditions_for_datatable
|
30
|
+
else
|
31
|
+
build_conditions_for_selected_columns
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_conditions_for_datatable
|
36
|
+
search_for = datatable.search.value.split(' ')
|
37
|
+
criteria = search_for.inject([]) do |criteria, atom|
|
38
|
+
search = Datatable::SimpleSearch.new({ value: atom, regex: datatable.search.regexp? })
|
39
|
+
criteria << searchable_columns.map do |simple_column|
|
40
|
+
simple_column.search = search
|
41
|
+
simple_column.search_query
|
42
|
+
end.reduce(:or)
|
43
|
+
end.reduce(:and)
|
44
|
+
criteria
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_conditions_for_selected_columns
|
48
|
+
search_columns.map(&:search_query).reduce(:and)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Datatable
|
4
|
+
module Generators
|
5
|
+
class ConfigGenerator < ::Rails::Generators::Base
|
6
|
+
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
7
|
+
desc <<DESC
|
8
|
+
Description:
|
9
|
+
Creates an initializer file for AjaxDatatablesRails configuration at config/initializers.
|
10
|
+
DESC
|
11
|
+
|
12
|
+
def copy_config_file
|
13
|
+
template 'ajax_datatables_rails_config.rb', 'config/initializers/ajax_datatables_rails.rb'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Generators
|
5
|
+
class DatatableGenerator < ::Rails::Generators::Base
|
6
|
+
desc 'Creates a *_datatable model in the app/datatables directory.'
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
argument :name, type: :string
|
9
|
+
|
10
|
+
def generate_datatable
|
11
|
+
template 'datatable.rb', File.join(
|
12
|
+
'app/datatables', "#{datatable_path}.rb"
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def datatable_name
|
17
|
+
datatable_path.classify
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def datatable_path
|
22
|
+
"#{name.underscore}_datatable"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class <%= datatable_name %> < AjaxDatatablesRails::Base
|
2
|
+
|
3
|
+
def view_columns
|
4
|
+
# Declare strings in this format: ModelName.column_name
|
5
|
+
# or in aliased_join_table.column_name format
|
6
|
+
@view_columns ||= {
|
7
|
+
# id: { source: "User.id", cond: :eq },
|
8
|
+
# name: { source: "User.name", cond: :like }
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def data
|
13
|
+
records.map do |record|
|
14
|
+
{
|
15
|
+
# example:
|
16
|
+
# id: record.id,
|
17
|
+
# name: record.name
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def get_raw_records
|
25
|
+
# insert query here
|
26
|
+
end
|
27
|
+
|
28
|
+
# ==== These methods represent the basic operations to perform on records
|
29
|
+
# and feel free to override them
|
30
|
+
|
31
|
+
# def filter_records(records)
|
32
|
+
# end
|
33
|
+
|
34
|
+
# def sort_records(records)
|
35
|
+
# end
|
36
|
+
|
37
|
+
# def paginate_records(records)
|
38
|
+
# end
|
39
|
+
|
40
|
+
# ==== Insert 'presenter'-like methods below if necessary
|
41
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AjaxDatatablesRails::Base do
|
4
|
+
describe 'an instance' do
|
5
|
+
let(:view) { double('view', params: sample_params) }
|
6
|
+
|
7
|
+
it 'requires a view_context' do
|
8
|
+
expect { AjaxDatatablesRails::Base.new }.to raise_error ArgumentError
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'accepts an options hash' do
|
12
|
+
datatable = AjaxDatatablesRails::Base.new(view, foo: 'bar')
|
13
|
+
expect(datatable.options).to eq(foo: 'bar')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'Public API' do
|
18
|
+
let(:view) { double('view', params: sample_params) }
|
19
|
+
let(:datatable) { AjaxDatatablesRails::Base.new(view) }
|
20
|
+
|
21
|
+
describe '#view_columns' do
|
22
|
+
it 'raises an error if not defined by the user' do
|
23
|
+
expect { datatable.view_columns }.to raise_error AjaxDatatablesRails::NotImplemented
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'child class implements view_columns' do
|
27
|
+
it 'expects an array based defining columns' do
|
28
|
+
datatable = SampleDatatable.new(view)
|
29
|
+
expect(datatable.view_columns).to be_a(Array)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'expects a hash based defining columns' do
|
33
|
+
datatable = ComplexDatatable.new(view)
|
34
|
+
expect(datatable.view_columns).to be_a(Hash)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#data' do
|
40
|
+
it 'raises an error if not defined by the user' do
|
41
|
+
expect { datatable.data }.to raise_error AjaxDatatablesRails::NotImplemented
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'child class implements data' do
|
45
|
+
let(:datatable) { ComplexDatatable.new(view) }
|
46
|
+
|
47
|
+
it 'can return an array of hashes' do
|
48
|
+
allow(datatable).to receive(:data) { [{}, {}] }
|
49
|
+
expect(datatable.data).to be_a(Array)
|
50
|
+
item = datatable.data.first
|
51
|
+
expect(item).to be_a(Hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'can return an array of arrays' do
|
55
|
+
allow(datatable).to receive(:data) { [[], []] }
|
56
|
+
expect(datatable.data).to be_a(Array)
|
57
|
+
item = datatable.data.first
|
58
|
+
expect(item).to be_a(Array)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#get_raw_records' do
|
65
|
+
it 'raises an error if not defined by the user' do
|
66
|
+
expect { datatable.get_raw_records }.to raise_error AjaxDatatablesRails::NotImplemented
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'Private API' do
|
72
|
+
let(:view) { double('view', params: sample_params) }
|
73
|
+
let(:datatable) { ComplexDatatable.new(view) }
|
74
|
+
|
75
|
+
before(:each) do
|
76
|
+
allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:orm) { nil }
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'fetch records' do
|
80
|
+
it 'raises an error if it does not include an ORM module' do
|
81
|
+
expect { datatable.send(:fetch_records) }.to raise_error
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'filter records' do
|
86
|
+
it 'raises an error if it does not include an ORM module' do
|
87
|
+
expect { datatable.send(:filter_records) }.to raise_error
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'sort records' do
|
92
|
+
it 'raises an error if it does not include an ORM module' do
|
93
|
+
expect { datatable.send(:sort_records) }.to raise_error
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'paginate records' do
|
98
|
+
it 'raises an error if it does not include an ORM module' do
|
99
|
+
expect { datatable.send(:paginate_records) }.to raise_error
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe 'helper methods' do
|
104
|
+
describe '#offset' do
|
105
|
+
it 'defaults to 0' do
|
106
|
+
default_view = double('view', params: {})
|
107
|
+
datatable = AjaxDatatablesRails::Base.new(default_view)
|
108
|
+
expect(datatable.datatable.send(:offset)).to eq(0)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'matches the value on view params[:start] minus 1' do
|
112
|
+
paginated_view = double('view', params: { start: '11' })
|
113
|
+
datatable = AjaxDatatablesRails::Base.new(paginated_view)
|
114
|
+
expect(datatable.datatable.send(:offset)).to eq(10)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#page' do
|
119
|
+
it 'calculates page number from params[:start] and #per_page' do
|
120
|
+
paginated_view = double('view', params: { start: '11' })
|
121
|
+
datatable = AjaxDatatablesRails::Base.new(paginated_view)
|
122
|
+
expect(datatable.datatable.send(:page)).to eq(2)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#per_page' do
|
127
|
+
it 'defaults to 10' do
|
128
|
+
datatable = AjaxDatatablesRails::Base.new(view)
|
129
|
+
expect(datatable.datatable.send(:per_page)).to eq(10)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'matches the value on view params[:length]' do
|
133
|
+
other_view = double('view', params: { length: 20 })
|
134
|
+
datatable = AjaxDatatablesRails::Base.new(other_view)
|
135
|
+
expect(datatable.datatable.send(:per_page)).to eq(20)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AjaxDatatablesRails do
|
4
|
+
describe "configurations" do
|
5
|
+
context "configurable from outside" do
|
6
|
+
before(:each) do
|
7
|
+
AjaxDatatablesRails.configure do |config|
|
8
|
+
config.db_adapter = :mysql
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have custom value" do
|
13
|
+
expect(AjaxDatatablesRails.config.db_adapter).to eq(:mysql)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe AjaxDatatablesRails::Configuration do
|
20
|
+
let(:config) { AjaxDatatablesRails::Configuration.new }
|
21
|
+
|
22
|
+
describe "default config" do
|
23
|
+
it "default orm should :active_record" do
|
24
|
+
expect(config.orm).to eq(:active_record)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "default db_adapter should :pg (postgresql)" do
|
28
|
+
expect(config.db_adapter).to eq(:pg)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "custom config" do
|
33
|
+
it 'should accept db_adapter custom value' do
|
34
|
+
config.db_adapter = :mysql
|
35
|
+
expect(config.db_adapter).to eq(:mysql)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'accepts a custom orm value' do
|
39
|
+
config.orm = :mongoid
|
40
|
+
expect(config.orm).to eq(:mongoid)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'AjaxDatatablesRails::Datatable::Column' do
|
4
|
+
let(:view) { double('view', params: sample_params) }
|
5
|
+
let(:datatable) { ComplexDatatable.new(view) }
|
6
|
+
before {
|
7
|
+
datatable.params[:columns] = {"0"=>{"data"=>"username", "name"=>"", "searchable"=>"true", "orderable"=>"true", "search"=>{"value"=>"searchvalue", "regex"=>"false"}}}
|
8
|
+
}
|
9
|
+
|
10
|
+
describe 'helper methods' do
|
11
|
+
describe 'order methods' do
|
12
|
+
let(:column) { datatable.datatable.columns.first }
|
13
|
+
|
14
|
+
it 'should be orderable' do
|
15
|
+
expect(column.orderable?).to eq(true)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be searchable' do
|
19
|
+
expect(column.searchable?).to eq(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should have connected to id column' do
|
23
|
+
expect(column.data).to eq('username')
|
24
|
+
end
|
25
|
+
|
26
|
+
context '#search' do
|
27
|
+
it 'child class' do
|
28
|
+
expect(column.search).to be_a(AjaxDatatablesRails::Datatable::SimpleSearch)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should have search value' do
|
32
|
+
expect(column.search.value).to eq('searchvalue')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should not regex' do
|
36
|
+
expect(column.search.regexp?).to eq false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#cond' do
|
41
|
+
it 'should be :like by default' do
|
42
|
+
expect(column.cond).to eq(:like)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#source' do
|
47
|
+
it 'should be :like by default' do
|
48
|
+
expect(column.source).to eq('User.username')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#search_query' do
|
53
|
+
it 'should buld search query' do
|
54
|
+
expect(column.search_query.to_sql).to include('%searchvalue%')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#sort_query' do
|
59
|
+
it 'should build sort query' do
|
60
|
+
expect(column.sort_query).to eq('users.username')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'AjaxDatatablesRails::Datatable::Datatable' do
|
4
|
+
let(:view) { double('view', params: sample_params) }
|
5
|
+
let(:datatable) { ComplexDatatable.new(view).datatable }
|
6
|
+
let(:order_option) { {"0"=>{"column"=>"0", "dir"=>"asc"}, "1"=>{"column"=>"1", "dir"=>"desc"}} }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
AjaxDatatablesRails.configure do |config|
|
10
|
+
config.db_adapter = :sqlite
|
11
|
+
config.orm = :active_record
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'helper methods' do
|
16
|
+
describe 'order methods' do
|
17
|
+
it 'should be orderable' do
|
18
|
+
expect(datatable.orderable?).to eq(true)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should not be orderable' do
|
22
|
+
datatable.options[:order] = nil
|
23
|
+
expect(datatable.orderable?).to eq(false)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should have 2 orderable columns' do
|
27
|
+
datatable.options[:order] = order_option
|
28
|
+
expect(datatable.orders.count).to eq(2)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'first column ordered by ASC' do
|
32
|
+
datatable.options[:order] = order_option
|
33
|
+
expect(datatable.orders.first.send :dir).to eq('ASC')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'first column ordered by DESC' do
|
37
|
+
datatable.options[:order] = order_option
|
38
|
+
expect(datatable.orders.last.send :dir).to eq('DESC')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'child class' do
|
42
|
+
expect(datatable.orders.first).to be_a(AjaxDatatablesRails::Datatable::SimpleOrder)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'search methods' do
|
47
|
+
it 'should be searchable' do
|
48
|
+
datatable.options[:search][:value] = 'atom'
|
49
|
+
expect(datatable.searchable?).to eq(true)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should not be searchable' do
|
53
|
+
datatable.options[:search][:value] = nil
|
54
|
+
expect(datatable.searchable?).to eq(false)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'child class' do
|
58
|
+
expect(datatable.search).to be_a(AjaxDatatablesRails::Datatable::SimpleSearch)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'columns methods' do
|
64
|
+
it 'should have 4 columns' do
|
65
|
+
expect(datatable.columns.count).to eq(4)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'child class' do
|
69
|
+
expect(datatable.columns.first).to be_a(AjaxDatatablesRails::Datatable::Column)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'option methods' do
|
75
|
+
before :each do
|
76
|
+
datatable.options[:start] = '50'
|
77
|
+
datatable.options[:length] = '15'
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'paginate?' do
|
81
|
+
expect(datatable.paginate?).to be(true)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'offset' do
|
85
|
+
expect(datatable.offset).to eq(45)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'page' do
|
89
|
+
expect(datatable.page).to eq(4)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'per_page' do
|
93
|
+
expect(datatable.per_page).to eq(15)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|