netzke-basepack 0.12.9 → 1.0.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +75 -44
- data/Gemfile +4 -2
- data/LICENSE +2 -6
- data/README.md +22 -24
- data/javascripts/basepack.js +0 -8
- data/javascripts/{columns.js → grid/columns.js} +59 -71
- data/javascripts/grid/event_handlers.js +218 -0
- data/javascripts/netzkeremotecombo.js +5 -13
- data/javascripts/tristate.js +62 -0
- data/javascripts/xdatetime.js +8 -37
- data/lib/netzke-basepack.rb +3 -2
- data/lib/netzke/basepack.rb +1 -1
- data/lib/netzke/basepack/action_column.rb +6 -23
- data/lib/netzke/basepack/active_record.rb +0 -6
- data/lib/netzke/basepack/attr_config.rb +20 -11
- data/lib/netzke/basepack/attribute_config.rb +10 -0
- data/lib/netzke/basepack/attributes.rb +196 -0
- data/lib/netzke/basepack/column_config.rb +47 -39
- data/lib/netzke/basepack/columns.rb +127 -97
- data/lib/netzke/basepack/data_accessor.rb +7 -48
- data/lib/netzke/basepack/data_adapters/abstract_adapter.rb +15 -17
- data/lib/netzke/basepack/data_adapters/active_record_adapter.rb +111 -90
- data/lib/netzke/basepack/dynamic_tab_panel.rb +3 -5
- data/lib/netzke/basepack/dynamic_tab_panel/{javascripts → client}/dynamic_tab_panel.js +6 -5
- data/lib/netzke/basepack/field_config.rb +30 -19
- data/lib/netzke/basepack/fields.rb +22 -12
- data/lib/netzke/basepack/grid_live_search.rb +1 -4
- data/lib/netzke/basepack/grid_live_search/{javascripts → client}/grid_live_search.js +9 -7
- data/lib/netzke/basepack/item_persistence.rb +3 -3
- data/lib/netzke/basepack/item_persistence/events_plugin.rb +8 -10
- data/lib/netzke/basepack/paging_form.rb +7 -11
- data/lib/netzke/basepack/paging_form/{javascripts → client}/paging_form.js +4 -4
- data/lib/netzke/basepack/query_builder.rb +12 -10
- data/lib/netzke/basepack/query_builder/{javascripts → client}/query_builder.js +14 -12
- data/lib/netzke/basepack/record_form_window.rb +8 -8
- data/lib/netzke/basepack/search_panel.rb +4 -6
- data/lib/netzke/basepack/search_panel/{javascripts → client}/condition_field.js +13 -16
- data/lib/netzke/basepack/search_panel/{javascripts → client}/search_panel.js +7 -7
- data/lib/netzke/basepack/search_window.rb +6 -6
- data/lib/netzke/basepack/simple_app/{javascripts → client}/statusbar_ext.js +0 -0
- data/lib/netzke/basepack/version.rb +1 -1
- data/lib/netzke/form/base.rb +166 -0
- data/lib/netzke/{basepack/form/javascripts/form.js → form/base/client/base.js} +77 -38
- data/lib/netzke/form/base/client/readonly_mode.css +4 -0
- data/lib/netzke/{basepack/form/javascripts → form/base/client}/readonly_mode.js +5 -5
- data/lib/netzke/form/endpoints.rb +33 -0
- data/lib/netzke/form/services.rb +74 -0
- data/lib/netzke/grid/actions.rb +52 -0
- data/lib/netzke/grid/base.rb +289 -0
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/advanced_search.js +5 -1
- data/lib/netzke/{basepack/grid/javascripts/grid.js → grid/base/client/base.js} +61 -53
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/extensions.js +19 -13
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/remember_selection.js +0 -1
- data/lib/netzke/grid/client.rb +8 -0
- data/lib/netzke/grid/components.rb +55 -0
- data/lib/netzke/grid/configuration.rb +72 -0
- data/lib/netzke/grid/endpoints.rb +99 -0
- data/lib/netzke/grid/permissions.rb +18 -0
- data/lib/netzke/grid/services.rb +141 -0
- data/lib/netzke/tree/base.rb +173 -0
- data/lib/netzke/{basepack/tree/javascripts/tree.js → tree/base/client/base.js} +55 -26
- data/lib/netzke/{basepack/tree/javascripts → tree/base/client}/extensions.js +7 -7
- data/lib/netzke/tree/endpoints.rb +34 -0
- data/lib/netzke/{basepack/viewport.rb → viewport/base.rb} +3 -3
- data/lib/netzke/{basepack/window.rb → window/base.rb} +7 -8
- data/lib/netzke/window/base/client/base.js +26 -0
- data/locales/de.yml +49 -33
- data/locales/en.yml +32 -39
- data/locales/es.yml +39 -25
- data/locales/nl.yml +39 -25
- data/locales/ru.yml +38 -25
- data/locales/uk.yml +40 -26
- data/stylesheets/basepack.css +10 -0
- metadata +48 -45
- data/javascripts/mixins/grid_event_handlers.js +0 -139
- data/lib/netzke/basepack/accordion.rb +0 -45
- data/lib/netzke/basepack/active_record/relation_extensions.rb +0 -27
- data/lib/netzke/basepack/form.rb +0 -131
- data/lib/netzke/basepack/form/endpoints.rb +0 -35
- data/lib/netzke/basepack/form/services.rb +0 -74
- data/lib/netzke/basepack/form/stylesheets/readonly_mode.css +0 -14
- data/lib/netzke/basepack/grid.rb +0 -570
- data/lib/netzke/basepack/grid/endpoints.rb +0 -111
- data/lib/netzke/basepack/grid/javascripts/edit_in_form.js +0 -51
- data/lib/netzke/basepack/grid/services.rb +0 -148
- data/lib/netzke/basepack/tab_panel.rb +0 -22
- data/lib/netzke/basepack/tab_panel/javascripts/tab_panel.js +0 -11
- data/lib/netzke/basepack/tree.rb +0 -269
- data/lib/netzke/basepack/window/javascripts/window.js +0 -26
- data/lib/netzke/basepack/wrap_lazy_loaded.rb +0 -29
@@ -2,57 +2,16 @@ module Netzke
|
|
2
2
|
module Basepack
|
3
3
|
# This module is included into such data-driven components as Grid, Form, PagingForm, etc.
|
4
4
|
module DataAccessor
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# Normalize array of attributes
|
11
|
-
# [:col1, "col2", {:name => :col3}] #=> [{:name => "col1"}, {:name => "col2"}, {:name => "col3"}]
|
12
|
-
def normalize_attrs(attrs)
|
13
|
-
attrs.map{ |a| normalize_attr(a) }
|
14
|
-
end
|
15
|
-
|
16
|
-
# Normalize an attribute, e.g.:
|
17
|
-
# :first_name =>
|
18
|
-
# {:name => "first_name"}
|
19
|
-
def normalize_attr(a)
|
20
|
-
a.is_a?(Symbol) || a.is_a?(String) ? {:name => a.to_s} : a.merge(:name => a[:name].to_s)
|
21
|
-
end
|
22
|
-
|
23
|
-
def association_attr?(attr)
|
24
|
-
!!attr[:name].to_s.index("__")
|
25
|
-
end
|
26
|
-
|
27
|
-
# Model class
|
28
|
-
def data_class
|
29
|
-
@data_class ||= config[:model].is_a?(String) ? config[:model].constantize : config[:model]
|
5
|
+
# Model class as specified in configuration. May be handy to override.
|
6
|
+
# Returns ORM model class.
|
7
|
+
def model
|
8
|
+
@model ||= config[:model].is_a?(String) ? config[:model].constantize : config[:model]
|
30
9
|
end
|
31
10
|
|
32
11
|
# Data adapter responsible for all DB-related operations.
|
33
|
-
# Note that if
|
34
|
-
def
|
35
|
-
@
|
36
|
-
end
|
37
|
-
|
38
|
-
# Mark an attribute as "virtual" by default, when it doesn't reflect a model column, or a model column of an association
|
39
|
-
def set_default_virtual(c)
|
40
|
-
c[:virtual] = data_adapter.virtual_attribute?(c) if c[:virtual].nil?
|
41
|
-
end
|
42
|
-
|
43
|
-
# Returns a hash of association attribute default values. Used when creating new records with association attributes that have a default value
|
44
|
-
def default_association_values(attr_hash) #:nodoc:
|
45
|
-
@_default_association_values ||= {}.tap do |values|
|
46
|
-
attr_hash.each_pair do |name,c|
|
47
|
-
next unless association_attr?(c) && c[:default_value]
|
48
|
-
|
49
|
-
assoc_name, assoc_method = c[:name].split '__'
|
50
|
-
assoc_class = data_adapter.class_for(assoc_name)
|
51
|
-
assoc_data_adapter = Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(assoc_class).new(assoc_class)
|
52
|
-
assoc_instance = assoc_data_adapter.find_record c[:default_value]
|
53
|
-
values[name] = assoc_instance.send(assoc_method)
|
54
|
-
end
|
55
|
-
end
|
12
|
+
# Note that if model is nil, AbstractAdapter will used.
|
13
|
+
def model_adapter
|
14
|
+
@model_adapter ||= Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(model).new(model)
|
56
15
|
end
|
57
16
|
end
|
58
17
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Netzke::Basepack::DataAdapters
|
2
2
|
# A concrete adapter should implement all the public instance methods of this adapter in order to support all the functionality of Basepack components.
|
3
3
|
class AbstractAdapter
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :model
|
5
5
|
|
6
6
|
# Returns primary key name of the model
|
7
7
|
def primary_key
|
@@ -18,7 +18,7 @@ module Netzke::Basepack::DataAdapters
|
|
18
18
|
[]
|
19
19
|
end
|
20
20
|
|
21
|
-
# Returns a list of model attribute
|
21
|
+
# Returns a list of model attribute names.
|
22
22
|
# For association columns the name can have the double-underscore format, e.g.: `author__first_name`.
|
23
23
|
# These attributes will be used by grids and forms to display default columns/fields.
|
24
24
|
def model_attributes
|
@@ -48,7 +48,7 @@ module Netzke::Basepack::DataAdapters
|
|
48
48
|
# [start]
|
49
49
|
# page number in pagination
|
50
50
|
# [scope]
|
51
|
-
# the scope as described in Netzke::
|
51
|
+
# the scope as described in Netzke::Grid::Base
|
52
52
|
# [filters]
|
53
53
|
# an array of hashes representing a filter query, where the hashes have the following keys:
|
54
54
|
# [attr]
|
@@ -75,7 +75,7 @@ module Netzke::Basepack::DataAdapters
|
|
75
75
|
#
|
76
76
|
# `params` is a hash that contains the following keys:
|
77
77
|
#
|
78
|
-
# * :scope - the scope as described in Netzke::
|
78
|
+
# * :scope - the scope as described in Netzke::Grid::Base
|
79
79
|
# * :filter - Ext filters
|
80
80
|
#
|
81
81
|
# The `columns` parameter may be used to use joins to address the n+1 query problem, and receives an array of column configurations
|
@@ -225,24 +225,22 @@ module Netzke::Basepack::DataAdapters
|
|
225
225
|
name.to_s.humanize
|
226
226
|
end
|
227
227
|
|
228
|
-
#
|
228
|
+
# Return root record for tree-like data
|
229
229
|
def root
|
230
|
-
|
230
|
+
model.root
|
231
231
|
end
|
232
232
|
|
233
|
-
|
234
|
-
|
235
|
-
r.children.extend_with(scope)
|
233
|
+
def find_record_children(r)
|
234
|
+
r.children
|
236
235
|
end
|
237
236
|
|
238
|
-
|
239
|
-
|
240
|
-
model_class.where(parent_id: nil).extend_with(scope)
|
237
|
+
def find_root_records
|
238
|
+
model.where(parent_id: nil)
|
241
239
|
end
|
242
240
|
|
243
241
|
# Does record respond to given method?
|
244
242
|
def model_respond_to?(method)
|
245
|
-
@
|
243
|
+
@model.instance_methods.include?(method)
|
246
244
|
end
|
247
245
|
|
248
246
|
# -- End of overridable methods
|
@@ -261,12 +259,12 @@ module Netzke::Basepack::DataAdapters
|
|
261
259
|
@subclasses << subclass
|
262
260
|
end
|
263
261
|
|
264
|
-
def self.adapter_class(
|
265
|
-
@subclasses.detect { |subclass| subclass.for_class?(
|
262
|
+
def self.adapter_class(model)
|
263
|
+
@subclasses.detect { |subclass| subclass.for_class?(model) } || AbstractAdapter
|
266
264
|
end
|
267
265
|
|
268
|
-
def initialize(
|
269
|
-
@
|
266
|
+
def initialize(model)
|
267
|
+
@model = model
|
270
268
|
end
|
271
269
|
end
|
272
270
|
end
|
@@ -1,22 +1,22 @@
|
|
1
1
|
module Netzke::Basepack::DataAdapters
|
2
2
|
# Implementation of {Netzke::Basepack::DataAdapters::AbstractAdapter}
|
3
3
|
class ActiveRecordAdapter < AbstractAdapter
|
4
|
-
def self.for_class?(
|
5
|
-
|
4
|
+
def self.for_class?(model)
|
5
|
+
model && model <= ActiveRecord::Base
|
6
6
|
end
|
7
7
|
|
8
8
|
def new_record(params = {})
|
9
|
-
@
|
9
|
+
@model.new(params)
|
10
10
|
end
|
11
11
|
|
12
12
|
def primary_key
|
13
|
-
@
|
13
|
+
@model.primary_key.to_s
|
14
14
|
end
|
15
15
|
|
16
16
|
def model_attributes
|
17
|
-
@
|
17
|
+
@model_attributes ||= attribute_names.map do |column_name|
|
18
18
|
# If it's named as foreign key of some association, then it's an association column
|
19
|
-
assoc = @
|
19
|
+
assoc = @model.reflect_on_all_associations.detect { |a| a.foreign_key == column_name }
|
20
20
|
|
21
21
|
if assoc && !assoc.options[:polymorphic]
|
22
22
|
candidates = %w{name title label} << assoc.klass.primary_key
|
@@ -26,71 +26,29 @@ module Netzke::Basepack::DataAdapters
|
|
26
26
|
column_name.to_sym
|
27
27
|
end
|
28
28
|
# auto set up the default value from the column settings
|
29
|
-
# c[:default_value] = @
|
29
|
+
# c[:default_value] = @model.columns_hash[column_name].default if @model.columns_hash[column_name].default
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
def attribute_names
|
34
|
-
@
|
35
|
-
end
|
36
|
-
|
37
|
-
def human_attribute_name(attr_name)
|
38
|
-
@model_class.human_attribute_name(attr_name)
|
34
|
+
@model.column_names
|
39
35
|
end
|
40
36
|
|
41
37
|
def attr_type(attr_name)
|
42
38
|
method, assoc = method_and_assoc(attr_name)
|
43
|
-
klass = assoc.nil? ? @
|
39
|
+
klass = assoc.nil? ? @model : assoc.klass
|
44
40
|
klass.columns_hash[method].try(:type) || :string
|
45
41
|
end
|
46
42
|
|
47
43
|
# Implementation for {AbstractAdapter#get_records}
|
48
44
|
def get_records(params, columns=[])
|
49
|
-
# build initial relation based on passed params
|
50
45
|
relation = get_relation(params)
|
51
46
|
|
52
|
-
|
53
|
-
columns.each do |c|
|
54
|
-
assoc, method = c[:name].split('__')
|
55
|
-
relation = relation.includes(assoc.to_sym).references(assoc.to_sym) if method
|
56
|
-
end
|
57
|
-
|
58
|
-
# apply sorting if needed
|
59
|
-
if params[:sorters]
|
60
|
-
sorters = Array.new(params[:sorters])
|
61
|
-
sorters.each do |sorter|
|
62
|
-
sorter["direction"] ||= 'ASC'
|
63
|
-
dir = sorter["direction"].downcase
|
64
|
-
column = columns.detect { |c| c[:name] == sorter["property"] }
|
65
|
-
column ||= {name: sorter["property"]} # stub column, as we may want to sort by a column that's not in the grid
|
66
|
-
relation = apply_sorting(relation, column, dir)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
#page = params[:limit] ? params[:start].to_i/params[:limit].to_i + 1 : 1
|
71
|
-
if params[:limit]
|
72
|
-
relation.offset(params[:start]).limit(params[:limit])
|
73
|
-
else
|
74
|
-
relation
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def apply_sorting(relation, column, dir)
|
79
|
-
assoc, method = column[:name].split('__')
|
47
|
+
relation = fix_nplus1_problem(relation, columns)
|
80
48
|
|
81
|
-
|
82
|
-
if column.has_key?(:sorting_scope)
|
83
|
-
relation = relation.send(column[:sorting_scope].to_sym, dir.to_sym)
|
84
|
-
else
|
85
|
-
relation = if method.nil?
|
86
|
-
relation.order("#{@model_class.table_name}.#{assoc} #{dir}")
|
87
|
-
else
|
88
|
-
assoc = @model_class.reflect_on_association(assoc.to_sym)
|
89
|
-
relation.includes(assoc.name).references(assoc.klass.table_name.to_sym).order("#{assoc.klass.table_name}.#{method} #{dir}")
|
90
|
-
end
|
91
|
-
end
|
49
|
+
relation = apply_sorting(relation, columns, params[:sorters])
|
92
50
|
|
93
|
-
relation
|
51
|
+
relation = apply_offset(relation, params)
|
94
52
|
end
|
95
53
|
|
96
54
|
def count_records(params, columns=[])
|
@@ -107,7 +65,7 @@ module Netzke::Basepack::DataAdapters
|
|
107
65
|
end
|
108
66
|
|
109
67
|
def get_assoc_property_type assoc_name, prop_name
|
110
|
-
if prop_name && assoc = @
|
68
|
+
if prop_name && assoc = @model.reflect_on_association(assoc_name)
|
111
69
|
assoc_column = assoc.klass.columns_hash[prop_name.to_s]
|
112
70
|
assoc_column.try(:type)
|
113
71
|
end
|
@@ -120,7 +78,7 @@ module Netzke::Basepack::DataAdapters
|
|
120
78
|
if assoc
|
121
79
|
return !assoc.klass.column_names.include?(method)
|
122
80
|
else
|
123
|
-
return !@
|
81
|
+
return !@model.column_names.include?(c[:name])
|
124
82
|
end
|
125
83
|
end
|
126
84
|
|
@@ -131,9 +89,16 @@ module Netzke::Basepack::DataAdapters
|
|
131
89
|
# Options for an asssociation attribute
|
132
90
|
|
133
91
|
relation = assoc.klass.all
|
134
|
-
relation =
|
92
|
+
relation = attr[:scope].call(relation) if attr[:scope].is_a?(Proc)
|
135
93
|
|
136
|
-
if
|
94
|
+
if attr[:filter_association_with]
|
95
|
+
relation = attr[:filter_association_with].call(relation, query).to_a
|
96
|
+
if attr[:getter]
|
97
|
+
relation.map{ |r| [r.id, attr[:getter].call(r)] }
|
98
|
+
else
|
99
|
+
relation.map{ |r| [r.id, r.send(method)] }
|
100
|
+
end
|
101
|
+
elsif assoc.klass.column_names.include?(method)
|
137
102
|
# apply query
|
138
103
|
assoc_arel_table = assoc.klass.arel_table
|
139
104
|
|
@@ -151,35 +116,37 @@ module Netzke::Basepack::DataAdapters
|
|
151
116
|
end
|
152
117
|
|
153
118
|
def distinct_combo_values(attr, query)
|
154
|
-
records = query.empty? ? @
|
119
|
+
records = query.empty? ? @model.find_by_sql("select distinct #{attr[:name]} from #{@model.table_name}") : @model.find_by_sql("select distinct #{attr[:name]} from #{@model.table_name} where #{attr[:name]} like '#{query}%'")
|
155
120
|
records.map{|r| [r.send(attr[:name]), r.send(attr[:name])]}
|
156
121
|
end
|
157
122
|
|
158
123
|
def foreign_key_for assoc_name
|
159
|
-
@
|
124
|
+
@model.reflect_on_association(assoc_name.to_sym).foreign_key
|
160
125
|
end
|
161
126
|
|
162
127
|
# Returns the model class for association columns
|
163
128
|
def class_for assoc_name
|
164
|
-
@
|
129
|
+
@model.reflect_on_association(assoc_name.to_sym).klass
|
165
130
|
end
|
166
131
|
|
167
132
|
def destroy(ids)
|
168
|
-
@
|
133
|
+
@model.destroy(ids)
|
169
134
|
end
|
170
135
|
|
171
136
|
# Returns a record by id.
|
172
137
|
# Respects the following options:
|
173
138
|
# * scope - will only return a record if it falls into the provided scope
|
174
139
|
def find_record(id, options = {})
|
175
|
-
scope = options[:scope] || {}
|
176
|
-
@
|
140
|
+
# scope = options[:scope] || {}
|
141
|
+
relation = @model.where(primary_key => id)
|
142
|
+
relation = options[:scope].call(relation) if options[:scope].is_a?(Proc)
|
143
|
+
relation.first
|
177
144
|
end
|
178
145
|
|
179
146
|
# Build a hash of foreign keys and the associated model
|
180
147
|
def hash_fk_model
|
181
148
|
foreign_keys = {}
|
182
|
-
@
|
149
|
+
@model.reflect_on_all_associations(:belongs_to).map{ |r|
|
183
150
|
foreign_keys[r.association_foreign_key.to_sym] = r.name
|
184
151
|
}
|
185
152
|
foreign_keys
|
@@ -187,10 +154,10 @@ module Netzke::Basepack::DataAdapters
|
|
187
154
|
|
188
155
|
# FIXME
|
189
156
|
def move_records(params)
|
190
|
-
if defined?(ActsAsList) && @
|
157
|
+
if defined?(ActsAsList) && @model.ancestors.include?(ActsAsList::InstanceMethods)
|
191
158
|
ids = JSON.parse(params[:ids]).reverse
|
192
159
|
ids.each_with_index do |id, i|
|
193
|
-
r = @
|
160
|
+
r = @model.find(id)
|
194
161
|
r.insert_at(params[:new_index].to_i + i + 1)
|
195
162
|
end
|
196
163
|
on_data_changed # copypaste nonsense
|
@@ -216,21 +183,21 @@ module Netzke::Basepack::DataAdapters
|
|
216
183
|
end
|
217
184
|
|
218
185
|
def human_attribute_name(name)
|
219
|
-
@
|
186
|
+
@model.human_attribute_name(name)
|
220
187
|
end
|
221
188
|
|
222
189
|
def record_value_for_attribute(r, a, through_association = false)
|
223
|
-
v = if a
|
224
|
-
a[:getter].call(r)
|
225
|
-
elsif r.respond_to?("#{a[:name]}")
|
226
|
-
r.send("#{a[:name]}")
|
227
|
-
elsif association_attr?(a)
|
190
|
+
v = if association_attr?(a)
|
228
191
|
split = a[:name].to_s.split(/\.|__/)
|
229
|
-
assoc = @
|
192
|
+
assoc = @model.reflect_on_association(split.first.to_sym)
|
230
193
|
if through_association
|
231
|
-
split.inject(r) do |r,m| # Do we *really* need to descend deeper than 1 level?
|
194
|
+
split.inject(r) do |r, m| # Do we *really* need to descend deeper than 1 level?
|
232
195
|
return nil if r.nil?
|
233
|
-
|
196
|
+
|
197
|
+
# On the last iteration call the getter block
|
198
|
+
if a[:getter] && split.last.equal?(m)
|
199
|
+
a[:getter].call(r)
|
200
|
+
elsif r.respond_to?(m)
|
234
201
|
r.send(m)
|
235
202
|
else
|
236
203
|
logger.warn "Netzke: Wrong attribute name: #{a[:name]}" unless r.nil?
|
@@ -240,6 +207,11 @@ module Netzke::Basepack::DataAdapters
|
|
240
207
|
else
|
241
208
|
r.send("#{assoc.options[:foreign_key] || assoc.name.to_s.foreign_key}")
|
242
209
|
end
|
210
|
+
elsif a[:getter]
|
211
|
+
a[:getter].call(r)
|
212
|
+
elsif r.respond_to?("#{a[:name]}")
|
213
|
+
r.send("#{a[:name]}")
|
214
|
+
|
243
215
|
# the composite_primary_keys gem produces [Key1,Key2...] and [Value1,Value2...]
|
244
216
|
# on primary_key and id requests. Basepack::AttrConfig converts the keys-array to an String.
|
245
217
|
elsif primary_key.try(:to_s) == a[:name]
|
@@ -253,13 +225,11 @@ module Netzke::Basepack::DataAdapters
|
|
253
225
|
end
|
254
226
|
|
255
227
|
def set_record_value_for_attribute(record, attr, value)
|
256
|
-
::Rails.logger.debug "\n!!! attr: #{attr.inspect}\n"
|
257
228
|
value = value.to_time_in_current_zone if value.is_a?(Date) # convert Date to Time
|
258
229
|
unless attr[:read_only]
|
259
230
|
if attr[:setter]
|
260
231
|
attr[:setter].call(record, value)
|
261
232
|
elsif record.respond_to?("#{attr[:name]}=")
|
262
|
-
::Rails.logger.debug "\n!!! value: #{value.inspect}\n"
|
263
233
|
record.send("#{attr[:name]}=", value)
|
264
234
|
elsif association_attr?(attr)
|
265
235
|
split = attr[:name].to_s.split(/\.|__/)
|
@@ -268,11 +238,11 @@ module Netzke::Basepack::DataAdapters
|
|
268
238
|
# set_value_for_attribute({:name => :assoc_1__assoc_2__method, :nested_attribute => true}, 100)
|
269
239
|
# =>
|
270
240
|
# record.assoc_1.assoc_2.method = 100
|
271
|
-
split.inject(record) { |r,m| m == split.last ? (r && r.send("#{m}=",
|
241
|
+
split.inject(record) { |r,m| m == split.last ? (r && r.send("#{m}=", value) && r.save) : r.send(m) }
|
272
242
|
else
|
273
243
|
if split.size == 2
|
274
244
|
# search for association and assign it to r
|
275
|
-
assoc = @
|
245
|
+
assoc = @model.reflect_on_association(split.first.to_sym)
|
276
246
|
assoc_method = split.last
|
277
247
|
if assoc
|
278
248
|
if assoc.macro == :has_one
|
@@ -290,7 +260,7 @@ module Netzke::Basepack::DataAdapters
|
|
290
260
|
record.send("#{assoc.foreign_key}=", value.to_i < 0 ? nil : value)
|
291
261
|
end
|
292
262
|
else
|
293
|
-
logger.warn "Netzke: Association #{assoc} is not known for class #{@
|
263
|
+
logger.warn "Netzke: Association #{assoc} is not known for class #{@model}"
|
294
264
|
end
|
295
265
|
else
|
296
266
|
logger.warn "Netzke: Wrong attribute name: #{attr[:name]}"
|
@@ -304,13 +274,13 @@ module Netzke::Basepack::DataAdapters
|
|
304
274
|
# Else returns [attr_name]
|
305
275
|
def method_and_assoc(attr_name)
|
306
276
|
assoc_name, method = attr_name.to_s.split('__')
|
307
|
-
assoc = @
|
277
|
+
assoc = @model.reflect_on_association(assoc_name.to_sym) if method
|
308
278
|
assoc.nil? ? [attr_name] : [method, assoc]
|
309
279
|
end
|
310
280
|
|
311
281
|
# An ActiveRecord::Relation instance encapsulating all the necessary conditions.
|
312
282
|
def get_relation(params = {})
|
313
|
-
relation = @
|
283
|
+
relation = @model.all
|
314
284
|
|
315
285
|
query = params[:query]
|
316
286
|
|
@@ -337,17 +307,20 @@ module Netzke::Basepack::DataAdapters
|
|
337
307
|
if params[:filters]
|
338
308
|
and_query = params[:filters]
|
339
309
|
and_query.each do |q|
|
340
|
-
|
341
|
-
relation = prok.call(relation, q[:value], q[:operator])
|
342
|
-
and_query.delete(q)
|
343
|
-
end
|
310
|
+
relation = q[:proc].call(relation, q[:value], q[:operator]) if q[:proc]
|
344
311
|
end
|
345
312
|
|
313
|
+
and_query.delete_if{|q| q[:proc] }
|
314
|
+
|
346
315
|
# apply other, non-Proc filters
|
347
316
|
relation = relation.where(predicates_for_and_conditions(and_query))
|
348
317
|
end
|
349
318
|
|
350
|
-
|
319
|
+
if params[:scope].is_a?(Proc)
|
320
|
+
relation = params[:scope].call(relation)
|
321
|
+
else
|
322
|
+
raise ArgumentError, "Expected scope to be a Proc, got #{params[:scope].class}" unless params[:scope].nil?
|
323
|
+
end
|
351
324
|
|
352
325
|
@relation = relation
|
353
326
|
end
|
@@ -361,7 +334,7 @@ module Netzke::Basepack::DataAdapters
|
|
361
334
|
attr = q[:attr]
|
362
335
|
method, assoc = method_and_assoc(attr)
|
363
336
|
|
364
|
-
arel_table = assoc ? Arel::Table.new(assoc.klass.table_name.to_sym) : @
|
337
|
+
arel_table = assoc ? Arel::Table.new(assoc.klass.table_name.to_sym) : @model.arel_table
|
365
338
|
|
366
339
|
value = q["value"]
|
367
340
|
op = q["operator"]
|
@@ -420,7 +393,55 @@ module Netzke::Basepack::DataAdapters
|
|
420
393
|
end
|
421
394
|
end
|
422
395
|
|
423
|
-
|
396
|
+
protected
|
397
|
+
|
398
|
+
# Addresses the n+1 query problem
|
399
|
+
# Returns updated relation
|
400
|
+
def fix_nplus1_problem(relation, columns)
|
401
|
+
columns.reduce(relation) do |rel, c|
|
402
|
+
assoc, method = c[:name].split('__')
|
403
|
+
method ? rel.includes(assoc.to_sym).references(assoc.to_sym) : rel
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def apply_sorting(relation, columns, sorters)
|
408
|
+
return relation if sorters.blank?
|
409
|
+
|
410
|
+
sorters = Array.new(sorters)
|
411
|
+
|
412
|
+
relation = relation.reorder("") # reset eventual default_scope ordering
|
413
|
+
|
414
|
+
sorters.reduce(relation) do |rel, sorter|
|
415
|
+
sorter["direction"] ||= 'ASC'
|
416
|
+
dir = sorter["direction"].downcase
|
417
|
+
column = columns.detect { |c| c[:name] == sorter["property"] }
|
418
|
+
column ||= {name: sorter["property"]} # stub column, as we may want to sort by a column that's not in the grid
|
419
|
+
apply_column_sorting(rel, column, dir)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def apply_column_sorting(relation, column, dir)
|
424
|
+
assoc, method = column[:name].split('__')
|
425
|
+
|
426
|
+
# if a sorting scope is set, call the scope with the given direction
|
427
|
+
if column[:sorting_scope].is_a?(Proc)
|
428
|
+
column[:sorting_scope].call(relation, dir.to_sym)
|
429
|
+
else
|
430
|
+
if method.nil?
|
431
|
+
relation.order("#{@model.table_name}.#{assoc} #{dir}")
|
432
|
+
else
|
433
|
+
assoc = @model.reflect_on_association(assoc.to_sym)
|
434
|
+
relation.includes(assoc.name).references(assoc.klass.table_name.to_sym).order("#{assoc.klass.table_name}.#{method} #{dir}")
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
def apply_offset(relation, params)
|
440
|
+
return relation if params[:limit].blank?
|
441
|
+
relation.offset(params[:start]).limit(params[:limit])
|
442
|
+
end
|
443
|
+
|
444
|
+
private
|
424
445
|
|
425
446
|
def logger
|
426
447
|
Netzke::Base.logger
|