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 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