rails-tables 0.3.3 → 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.
- data/app/tables/column.rb +17 -20
- data/app/tables/datatable.rb +50 -38
- data/lib/rails-tables/model_additions.rb +10 -21
- data/lib/rails-tables/version.rb +1 -1
- metadata +20 -4
- data/app/tables/search.rb +0 -56
data/app/tables/column.rb
CHANGED
@@ -1,17 +1,22 @@
|
|
1
1
|
class Column
|
2
2
|
|
3
|
-
attr_accessor :name, :
|
4
|
-
def initialize(name, *args)
|
3
|
+
attr_accessor :model, :name, :method, :column_source, :render_with, :sortable, :searchable, :blank_value
|
4
|
+
def initialize(model, name, *args)
|
5
|
+
self.model = model
|
5
6
|
self.name = name
|
6
7
|
|
7
8
|
attributes = args.pop || {}
|
8
|
-
self.
|
9
|
-
self.
|
9
|
+
self.method = attributes.fetch(:method, name)
|
10
|
+
self.column_source = attributes.fetch(:column_source, '')
|
10
11
|
self.render_with = attributes.fetch(:render_with, :default_render)
|
11
12
|
self.sortable = attributes.fetch(:sortable, true)
|
13
|
+
self.searchable = attributes.fetch(:searchable, true)
|
12
14
|
self.blank_value = attributes.fetch(:blank_value, '–')
|
13
15
|
|
14
16
|
define_singleton_method :render do |view, object|
|
17
|
+
self.column_source.split('.').each do |relation|
|
18
|
+
object = object.try(:send, relation)
|
19
|
+
end
|
15
20
|
if self.render_with.kind_of? Symbol
|
16
21
|
content = self.send(self.render_with, view, object)
|
17
22
|
else
|
@@ -21,39 +26,31 @@ class Column
|
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
24
|
-
def render(object)
|
25
|
-
self.relation_chain.each do |relation|
|
26
|
-
object = object.send(relation)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
29
|
def default_render(view, object)
|
32
|
-
property = object.send
|
30
|
+
property = object.try(:send, self.method)
|
33
31
|
property if not property.nil?
|
34
32
|
end
|
35
33
|
def self_referential_link(view, object)
|
36
|
-
property = object.send
|
34
|
+
property = object.try(:send, self.method)
|
37
35
|
view.link_to property, object if not property.nil?
|
38
36
|
end
|
39
37
|
def related_link(view, object)
|
40
|
-
property = object.send
|
38
|
+
property = object.try(:send, self.method)
|
41
39
|
view.link_to property, property if not property.nil?
|
42
40
|
end
|
43
|
-
def related_link_list(view,
|
44
|
-
|
45
|
-
property.collect { |related_object| related_link(view, related_object) }.join(', ') if not property.nil?
|
41
|
+
def related_link_list(view, objects)
|
42
|
+
objects.map{ |object| related_link(view, object) }.reject(&:nil?).join(', ') if not objects.nil?
|
46
43
|
end
|
47
44
|
def time(view, object)
|
48
|
-
property = object.send
|
45
|
+
property = object.try(:send, self.method)
|
49
46
|
property.strftime("%I:%M%p") if not property.nil?
|
50
47
|
end
|
51
48
|
def date(view, object)
|
52
|
-
property = object.send
|
49
|
+
property = object.try(:send, self.method)
|
53
50
|
property.strftime("%m/%d/%Y") if not property.nil?
|
54
51
|
end
|
55
52
|
def datetime(view, object)
|
56
|
-
property = object.send
|
53
|
+
property = object.try(:send, self.method)
|
57
54
|
property.strftime("%m/%d/%Y at %I:%M%p") if not property.nil?
|
58
55
|
end
|
59
56
|
|
data/app/tables/datatable.rb
CHANGED
@@ -12,15 +12,13 @@ class_attribute :source
|
|
12
12
|
self.source = Rails.application.routes.url_helpers.send(source, format: "json")
|
13
13
|
end
|
14
14
|
|
15
|
-
class_attribute :
|
16
|
-
self.defaults = {
|
17
|
-
initial_orderings: {},
|
18
|
-
}
|
15
|
+
class_attribute :initial_orderings
|
19
16
|
def self.initial_ordering(orderings)
|
20
|
-
self.
|
17
|
+
self.set_initial_orderings orderings
|
21
18
|
end
|
22
|
-
def self.
|
23
|
-
self.
|
19
|
+
def self.set_initial_orderings(orderings)
|
20
|
+
self.initial_orderings = {} if self.initial_orderings.nil?
|
21
|
+
self.initial_orderings.merge! orderings
|
24
22
|
end
|
25
23
|
|
26
24
|
def html_data
|
@@ -28,8 +26,8 @@ self.defaults = {
|
|
28
26
|
if self.class.source?
|
29
27
|
options[:source] = self.class.source
|
30
28
|
end
|
31
|
-
|
32
|
-
self.class.
|
29
|
+
unless self.initial_orderings.nil?
|
30
|
+
self.class.initial_orderings.each do |column, order|
|
33
31
|
options["#{column}_ordering"] = order.to_s
|
34
32
|
end
|
35
33
|
end
|
@@ -54,62 +52,76 @@ attr_accessor :view, :scopes
|
|
54
52
|
}
|
55
53
|
end
|
56
54
|
|
57
|
-
class_attribute :columns, :
|
55
|
+
class_attribute :columns, :column_factory
|
58
56
|
def self.column(name, *args)
|
59
57
|
arguments = args.pop || {}
|
60
|
-
self.
|
61
|
-
self.
|
58
|
+
self.column_factory = [] if self.column_factory.nil?
|
59
|
+
self.column_factory << { name: name, args: arguments }
|
62
60
|
end
|
63
|
-
def
|
64
|
-
|
65
|
-
self.searches = [] if self.searches.nil?
|
66
|
-
self.searches << Search.new(name, self, arguments)
|
61
|
+
def columns
|
62
|
+
@columns ||= self.column_factory.map{ |new_column| Column.new(self.model, new_column[:name], new_column[:args]) }
|
67
63
|
end
|
64
|
+
|
65
|
+
class_attribute :match_any
|
68
66
|
self.match_any = true
|
69
67
|
def self.match_all_columns
|
70
68
|
self.match_any = false
|
71
69
|
end
|
72
70
|
|
71
|
+
attr_accessor :joins
|
72
|
+
def joins
|
73
|
+
@joins ||= self.columns.map(&:column_source).uniq.reject(&:blank?)
|
74
|
+
end
|
75
|
+
attr_accessor :searches
|
76
|
+
def searches
|
77
|
+
@searches ||= self.columns.select(&:searchable).select{|c| c.column_source.present?}
|
78
|
+
end
|
79
|
+
|
73
80
|
private
|
74
81
|
|
75
82
|
def objects
|
83
|
+
query = self.model
|
84
|
+
self.joins.each do |join|
|
85
|
+
query = query.uniq.includes{ join.split('.').inject((strs.present? ? self : nil), :__send__).outer }
|
86
|
+
end
|
76
87
|
if sortable
|
77
|
-
|
78
|
-
|
79
|
-
objects = self.model
|
88
|
+
sort_expression = sort
|
89
|
+
query = query.reorder{ my{sort_expression} }#("#{sort_column} #{sort_direction}")
|
80
90
|
end
|
81
91
|
self.scopes.each do |scope|
|
82
|
-
|
92
|
+
query = scope.call(query)
|
83
93
|
end
|
84
94
|
if params[:sSearch].present?
|
85
|
-
|
95
|
+
search_expression = search(params[:sSearch])
|
96
|
+
query = query.where{ my{search_expression} }
|
86
97
|
end
|
87
|
-
|
88
|
-
|
98
|
+
query = query.paginate(page: page, per_page: per_page)
|
99
|
+
end
|
100
|
+
|
101
|
+
def sortable
|
102
|
+
self.columns.map{ |column| column.sortable }[params[:iSortCol_0].to_i] unless params[:bUseDefaultSort] == 'true'
|
103
|
+
end
|
104
|
+
def sort
|
105
|
+
column = self.columns[params[:iSortCol_0].to_i]
|
106
|
+
direction = params[:sSortDir_0] == "asc" ? 1 : -1
|
107
|
+
Squeel::Nodes::KeyPath.new(column.column_source.split('.') << Squeel::Nodes::Order.new(column.method, direction))
|
89
108
|
end
|
90
109
|
|
91
|
-
def search(
|
92
|
-
|
93
|
-
|
94
|
-
|
110
|
+
def search(terms)
|
111
|
+
terms = terms.split if terms.is_a? String
|
112
|
+
self.searches.map do |column|
|
113
|
+
terms.map do |word|
|
114
|
+
Squeel::Nodes::KeyPath.new(column.column_source.split('.') << Squeel::Nodes::Stub.new(column.method)) =~ "%#{word}%"
|
115
|
+
end.compact.inject(&:|)
|
116
|
+
end.compact.inject(&:|)
|
95
117
|
end
|
96
|
-
|
118
|
+
|
97
119
|
def page
|
98
120
|
params[:iDisplayStart].to_i/per_page + 1
|
99
121
|
end
|
100
122
|
def per_page
|
101
123
|
params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10
|
102
124
|
end
|
103
|
-
|
104
|
-
def sortable
|
105
|
-
self.columns.map{ |column| column.sortable }[params[:iSortCol_0].to_i] unless params[:bUseDefaultSort] == 'true'
|
106
|
-
end
|
107
|
-
def sort_column
|
108
|
-
self.columns.map(&:column_name)[params[:iSortCol_0].to_i]
|
109
|
-
end
|
110
|
-
def sort_direction
|
111
|
-
params[:sSortDir_0] == "asc" ? "asc" : "desc"
|
112
|
-
end
|
113
125
|
|
114
126
|
def data
|
115
127
|
objects.map do |object|
|
@@ -1,22 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
define_method "#{name}_search" do |terms|
|
9
|
-
searches =
|
10
|
-
self.datatable.searches.map do |search|
|
11
|
-
self.instance_exec search.column_name, terms, &search.search
|
12
|
-
end.inject do |t, expr|
|
13
|
-
if self.datatable.match_any
|
14
|
-
t | expr
|
15
|
-
else
|
16
|
-
t & expr
|
17
|
-
end
|
18
|
-
end
|
19
|
-
self.where{ searches }
|
20
|
-
end
|
1
|
+
module RailsTables::ModelAdditions
|
2
|
+
def has_datatable(*args)
|
3
|
+
arguments = args.pop || {}
|
4
|
+
name = arguments.fetch(:name, 'datatable')
|
5
|
+
klass = arguments.fetch(:klass, "#{self.name.pluralize.underscore}_datatable").camelize
|
6
|
+
cattr_accessor name
|
7
|
+
self.send("#{name}=", klass.constantize.new(name, self))
|
21
8
|
end
|
22
|
-
end
|
9
|
+
end
|
10
|
+
|
11
|
+
ActiveRecord::Base.extend RailsTables::ModelAdditions
|
data/lib/rails-tables/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-tables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '3.1'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activerecord
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: jquery-datatables-rails
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,7 +107,8 @@ dependencies:
|
|
91
107
|
- - ~>
|
92
108
|
- !ruby/object:Gem::Version
|
93
109
|
version: 1.0.11
|
94
|
-
description:
|
110
|
+
description: RailsTables is a simple DSL built on top of jquery-datatables-rails to
|
111
|
+
quickly compose performant jQuery datatables for your Rails app.
|
95
112
|
email:
|
96
113
|
- dev@chriskeele.com
|
97
114
|
executables: []
|
@@ -101,7 +118,6 @@ files:
|
|
101
118
|
- app/assets/javascripts/rails-tables.js.coffee
|
102
119
|
- app/tables/column.rb
|
103
120
|
- app/tables/datatable.rb
|
104
|
-
- app/tables/search.rb
|
105
121
|
- config/routes.rb
|
106
122
|
- lib/rails-tables/engine.rb
|
107
123
|
- lib/rails-tables/model_additions.rb
|
data/app/tables/search.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
class Search
|
2
|
-
cattr_accessor :strategies
|
3
|
-
self.strategies = {
|
4
|
-
contains_strategy: {
|
5
|
-
type: :string,
|
6
|
-
match_with: '%%%s%%'
|
7
|
-
},
|
8
|
-
starts_with_strategy: {
|
9
|
-
type: :string,
|
10
|
-
match_with: '%s%%'
|
11
|
-
},
|
12
|
-
ends_with_strategy: {
|
13
|
-
type: :string,
|
14
|
-
match_with: '%%%s'
|
15
|
-
}
|
16
|
-
}
|
17
|
-
attr_accessor :name, :table, :column_name, :search_with, :match_any, :split_terms
|
18
|
-
def initialize(name, table, *args)
|
19
|
-
self.name = name
|
20
|
-
self.table = table
|
21
|
-
|
22
|
-
attributes = args.pop || {}
|
23
|
-
self.column_name = attributes.fetch(:column_name, name)
|
24
|
-
self.search_with = attributes.fetch(:search_with, :contains_strategy)
|
25
|
-
self.match_any = attributes.fetch(:match_any, true)
|
26
|
-
self.split_terms = attributes.fetch(:split_terms, true)
|
27
|
-
|
28
|
-
|
29
|
-
define_singleton_method :search do
|
30
|
-
if self.search_with.kind_of? Symbol
|
31
|
-
strategy_builder(self.search_with, self.match_any, self.split_terms)
|
32
|
-
else
|
33
|
-
self.search_with(self.match_any, self.split_terms)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def strategy_builder(strategy_name, match_any, split_terms)
|
39
|
-
Proc.new do |field, terms|
|
40
|
-
if split_terms
|
41
|
-
terms = terms.split
|
42
|
-
else
|
43
|
-
terms = [terms]
|
44
|
-
end
|
45
|
-
terms.map{|s| Search.strategies[strategy_name][:match_with] % s}.map do |term|
|
46
|
-
Squeel::Nodes::Predicate.new(Squeel::Nodes::Stub.new(field), :matches, term)
|
47
|
-
end.inject do |t, expr|
|
48
|
-
if match_any
|
49
|
-
t | expr
|
50
|
-
else
|
51
|
-
t & expr
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|