Skip to content

Commit 1988e27

Browse files
committed
Edits project organization through namespaces and base classes.
* Adds `AjaxDatatablesRails` namespace to organize project. * Adds `AjaxDatatablesRails::Extensions` namespace to extract helper modules that provide behaviors. This namespace will serve as the storage place to add compatibility with different ORMs later on. * Replaces generator with `Rails::Generators::DatatableGenerator`, this will include our provided generator in the Rails namespace. * Removes `FilterdatatableGenerator`. It is not required.
1 parent 31536d4 commit 1988e27

File tree

21 files changed

+535
-143
lines changed

21 files changed

+535
-143
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# CHANGELOG
2+
3+
## 0.1.0
4+
* A fresh start. Changes base class name to: `DatatablesRails`.
5+
* Extracts pagination functions to mixable modules.
6+
* A user would have the option to stick to the base
7+
`DatatablesRails::Extensions::SimplePaginator` or replace it with
8+
`DatatablesRails::Extensions::Kaminari` or
9+
`DatatablesRails::Extensions::WillPaginate`, depending on what he/she is using to handle record pagination.
10+
* Removes dependency to pass in a model name to the generator. This way, the developer has more flexibility to implement whatever datatable feature is required.
11+
* Datatable constructor accepts an optional `options` hash to provide more flexibility. See [README](https://github.com/antillas21/ajax-datatables-rails/blob/master/README.md) for examples.

Rakefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,12 @@ require "bundler/gem_tasks"
33
require 'rspec/core/rake_task'
44

55
RSpec::Core::RakeTask.new(:spec)
6-
task default: :spec
6+
task :default => :spec
7+
8+
task :console do
9+
require 'pry'
10+
require 'rails'
11+
require 'ajax-datatables-rails'
12+
ARGV.clear
13+
Pry.start
14+
end

ajax-datatables-rails.gemspec

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
# -*- encoding: utf-8 -*-
2-
require File.expand_path('../lib/ajax-datatables-rails', __FILE__)
2+
lib = File.expand_path('../lib', __FILE__)
3+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4+
require 'ajax-datatables-rails/version'
35

46
Gem::Specification.new do |gem|
7+
gem.name = "ajax-datatables-rails"
8+
gem.version = AjaxDatatablesRails::VERSION
59
gem.authors = ["Joel Quenneville"]
610
gem.email = ["joel.quenneville@collegeplus.org"]
711
gem.description = %q{A gem that simplifies using datatables and hundreds of records via ajax}
812
gem.summary = %q{A wrapper around datatable's ajax methods that allow synchronization with server-side pagination in a rails app}
913
gem.homepage = ""
1014

11-
gem.files = `git ls-files`.split($\)
12-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15+
gem.files = Dir["{lib,spec}/**/*", "[A-Z]*"] - ["Gemfile.lock"]
16+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
1317
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14-
gem.name = "ajax-datatables-rails"
15-
gem.require_paths = ["lib"]
16-
gem.version = AjaxDatatablesRails::VERSION
18+
gem.require_path = "lib"
19+
20+
gem.add_dependency 'railties', '>= 3.1'
1721

1822
gem.add_development_dependency "rspec"
23+
gem.add_development_dependency "generator_spec"
24+
gem.add_development_dependency "pry"
25+
gem.add_development_dependency "rake"
26+
gem.add_development_dependency "rails", ">= 3.1.0"
1927
end

lib/ajax-datatables-rails.rb

Lines changed: 8 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,8 @@
1-
# require 'rails'
2-
3-
class AjaxDatatablesRails
4-
5-
class MethodError < StandardError; end
6-
7-
VERSION = '0.0.1'
8-
9-
attr_reader :columns, :model_name, :searchable_columns
10-
11-
def initialize(view)
12-
@view = view
13-
end
14-
15-
def method_missing(meth, *args, &block)
16-
@view.send(meth, *args, &block)
17-
end
18-
19-
def as_json(options = {})
20-
{
21-
sEcho: params[:sEcho].to_i,
22-
iTotalRecords: @model_name.count,
23-
iTotalDisplayRecords: filtered_record_count,
24-
aaData: data
25-
}
26-
end
27-
28-
private
29-
30-
def data
31-
raise MethodError, "The method `data' is not defined."
32-
end
33-
34-
def get_raw_records
35-
raise MethodError, "The method `get_raw_records' is not defined."
36-
end
37-
38-
def filtered_record_count
39-
search_records(get_raw_records).count
40-
end
41-
42-
def fetch_records
43-
search_records(sort_records(paginate_records(get_raw_records)))
44-
end
45-
46-
def paginate_records(records)
47-
records.offset((page - 1) * per_page).limit(per_page)
48-
end
49-
50-
def sort_records(records)
51-
records.order("#{sort_column} #{sort_direction}")
52-
end
53-
54-
def search_records(records)
55-
if params[:sSearch].present?
56-
query = @searchable_columns.map do |column|
57-
"#{column} LIKE :search"
58-
end.join(" OR ")
59-
records = records.where(query, search: "%#{params[:sSearch]}%")
60-
end
61-
return records
62-
end
63-
64-
def page
65-
params[:iDisplayStart].to_i/per_page + 1
66-
end
67-
68-
def per_page
69-
params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10
70-
end
71-
72-
def sort_column
73-
@columns[params[:iSortCol_0].to_i]
74-
end
75-
76-
def sort_direction
77-
params[:sSortDir_0] == "desc" ? "DESC" : "ASC"
78-
end
79-
end
1+
require 'ajax-datatables-rails/version'
2+
require 'ajax-datatables-rails/base'
3+
require 'ajax-datatables-rails/extensions/simple_paginator'
4+
require 'ajax-datatables-rails/extensions/kaminari'
5+
require 'ajax-datatables-rails/extensions/will_paginate'
6+
7+
module AjaxDatatablesRails
8+
end

lib/ajax-datatables-rails/base.rb

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
module AjaxDatatablesRails
2+
class Base
3+
extend Forwardable
4+
class MethodNotImplementedError < StandardError; end
5+
6+
attr_reader :view, :options, :sortable_columns, :searchable_columns
7+
def_delegator :@view, :params, :params
8+
9+
def initialize(view, options = {})
10+
@view = view
11+
@options = options
12+
end
13+
14+
def sortable_columns
15+
@sortable_columns ||= []
16+
end
17+
18+
def searchable_columns
19+
@searchable_columns ||= []
20+
end
21+
22+
def data
23+
fail(
24+
MethodNotImplementedError,
25+
'Please implement this method in your class.'
26+
)
27+
end
28+
29+
def get_raw_records
30+
fail(
31+
MethodNotImplementedError,
32+
'Please implement this method in your class.'
33+
)
34+
end
35+
36+
def as_json(options = {})
37+
{
38+
:sEcho => params[:sEcho].to_i,
39+
:iTotalRecords => get_raw_records.count,
40+
:iTotalDisplayRecords => filter_records(get_raw_records).count,
41+
:aaData => data
42+
}
43+
end
44+
45+
private
46+
47+
def records
48+
@records ||= fetch_records
49+
end
50+
51+
def fetch_records
52+
records = get_raw_records
53+
records = sort_records(records)
54+
records = filter_records(records)
55+
records = paginate_records(records)
56+
records
57+
end
58+
59+
def sort_records(records)
60+
records.order("#{sort_column} #{sort_direction}")
61+
end
62+
63+
def paginate_records(records)
64+
fail(
65+
MethodNotImplementedError,
66+
'Please mixin a pagination extension.'
67+
)
68+
end
69+
70+
def filter_records(records)
71+
records = simple_search(records)
72+
records = composite_search(records)
73+
records
74+
end
75+
76+
def simple_search(records)
77+
return records unless params[:sSearch]
78+
conditions = build_conditions_for(params[:sSearch])
79+
records = records.where(conditions) if conditions
80+
records
81+
end
82+
83+
def composite_search(records)
84+
conditions = aggregate_query
85+
records = records.where(conditions) if conditions
86+
records
87+
end
88+
89+
def build_conditions_for(query)
90+
searchable_columns.map { |col| search_condition(col, query) }.reduce(:or)
91+
end
92+
93+
def search_condition(column, value)
94+
model, column = column.split('.')
95+
model = model.singularize.titleize.constantize
96+
model.arel_table[column.to_sym].matches("%#{value}%")
97+
end
98+
99+
def aggregate_query
100+
conditions = searchable_columns.each_with_index.map do |column, index|
101+
value = params["sSearch_#{index}".to_sym]
102+
search_condition(column, value) if value
103+
end
104+
conditions.compact.reduce(:and)
105+
end
106+
107+
def offset
108+
(page - 1) * per_page
109+
end
110+
111+
def page
112+
(params[:iDisplayStart].to_i / per_page) + 1
113+
end
114+
115+
def per_page
116+
params.fetch(:iDisplayLength, 10).to_i
117+
end
118+
119+
def sort_column
120+
sortable_columns[params[:iSortCol_0].to_i]
121+
end
122+
123+
def sort_direction
124+
options = %w(desc asc)
125+
options.include?(params[:sSortDir_0]) ? params[:sSortDir_0].upcase : 'ASC'
126+
end
127+
end
128+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module AjaxDatatablesRails
2+
module Extensions
3+
module Kaminari
4+
5+
private
6+
7+
def paginate_records(records)
8+
records.page(page).per(per_page)
9+
end
10+
end
11+
end
12+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module AjaxDatatablesRails
2+
module Extensions
3+
module SimplePaginator
4+
5+
private
6+
7+
def paginate_records(records)
8+
records.offset(offset).limit(per_page)
9+
end
10+
end
11+
end
12+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module AjaxDatatablesRails
2+
module Extensions
3+
module WillPaginate
4+
5+
private
6+
7+
def paginate_records(records)
8+
records.paginate(:page => page, :per_page => per_page)
9+
end
10+
end
11+
end
12+
end

lib/ajax-datatables-rails/version.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module AjaxDatatablesRails
2+
VERSION = '0.1.0'
3+
end

lib/generators/ajaxdatatable/USAGE

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)