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 CHANGED
@@ -1,17 +1,22 @@
1
1
  class Column
2
2
 
3
- attr_accessor :name, :column_name, :referring_column_name, :render_with, :sortable, :blank_value
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.column_name = attributes.fetch(:column_name, name)
9
- self.referring_column_name = attributes.fetch(:referring_column_name, nil)
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(self.column_name)
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(self.column_name)
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(self.column_name)
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, object)
44
- property = object.send(self.referring_column_name)
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(self.column_name)
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(self.column_name)
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(self.column_name)
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
 
@@ -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 :defaults
16
- self.defaults = {
17
- initial_orderings: {},
18
- }
15
+ class_attribute :initial_orderings
19
16
  def self.initial_ordering(orderings)
20
- self.initial_orderings orderings
17
+ self.set_initial_orderings orderings
21
18
  end
22
- def self.initial_orderings(orderings)
23
- self.defaults[:initial_orderings].merge! orderings
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
- if self.defaults.has_key? :initial_orderings
32
- self.class.defaults[:initial_orderings].each do |column, order|
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, :searches, :authorized_scopes, :match_any
55
+ class_attribute :columns, :column_factory
58
56
  def self.column(name, *args)
59
57
  arguments = args.pop || {}
60
- self.columns = [] if self.columns.nil?
61
- self.columns << Column.new(name, arguments)
58
+ self.column_factory = [] if self.column_factory.nil?
59
+ self.column_factory << { name: name, args: arguments }
62
60
  end
63
- def self.search_by(name, *args)
64
- arguments = args.pop || {}
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
- objects = self.model.reorder("#{sort_column} #{sort_direction}")
78
- else
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
- objects = scope.call(objects)
92
+ query = scope.call(query)
83
93
  end
84
94
  if params[:sSearch].present?
85
- objects = objects.send("#{self.name}_search", params[:sSearch])
95
+ search_expression = search(params[:sSearch])
96
+ query = query.where{ my{search_expression} }
86
97
  end
87
- objects = objects.paginate(page: page, per_page: per_page)
88
- objects
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(objects, terms)
92
- self.searches.each do |search|
93
- objects = search.search(objects, terms)
94
- end
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
- def has_datatable(*args)
2
- arguments = args.pop || {}
3
- name = arguments.fetch(:name, 'datatable')
4
- klass = arguments.fetch(:klass, "#{self.name.pluralize}Datatable")
5
- cattr_accessor name
6
- self.send("#{name}=", klass.constantize.new(name, self))
7
- self.class.instance_eval do
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
@@ -1,3 +1,3 @@
1
1
  module RailsTables
2
- VERSION = "0.3.3"
2
+ VERSION = "0.4.0"
3
3
  end
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.3.3
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-21 00:00:00.000000000 Z
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: A clean jQuery datatables DSL.
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