rails-tables 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|