wice_grid_ms 3.6.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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.inch.yml +3 -0
- data/.rspec +3 -0
- data/.rubocop.yml +181 -0
- data/.travis.yml +22 -0
- data/CHANGELOG.md +714 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1518 -0
- data/Rakefile +59 -0
- data/SAVED_QUERIES_HOWTO.md +113 -0
- data/TODO.md +16 -0
- data/app/views/kaminari/wice_grid/_gap.html.erb +1 -0
- data/app/views/kaminari/wice_grid/_next_page.html.erb +1 -0
- data/app/views/kaminari/wice_grid/_page.html.erb +1 -0
- data/app/views/kaminari/wice_grid/_paginator.html.erb +19 -0
- data/app/views/kaminari/wice_grid/_prev_page.html.erb +1 -0
- data/config/locales/cz.yml +45 -0
- data/config/locales/de.yml +47 -0
- data/config/locales/en.yml +47 -0
- data/config/locales/es.yml +47 -0
- data/config/locales/fr.yml +45 -0
- data/config/locales/is.yml +46 -0
- data/config/locales/it.yml +38 -0
- data/config/locales/ja.yml +47 -0
- data/config/locales/nl.yml +45 -0
- data/config/locales/pt-BR.yml +36 -0
- data/config/locales/pt.yml +45 -0
- data/config/locales/ru.yml +45 -0
- data/config/locales/sk.yml +45 -0
- data/config/locales/uk.yml +45 -0
- data/config/locales/zh.yml +45 -0
- data/lib/generators/wice_grid/add_migration_for_serialized_queries_generator.rb +20 -0
- data/lib/generators/wice_grid/install_generator.rb +14 -0
- data/lib/generators/wice_grid/templates/create_wice_grid_serialized_queries.rb +14 -0
- data/lib/generators/wice_grid/templates/wice_grid_config.rb +192 -0
- data/lib/wice/active_record_column_wrapper.rb +123 -0
- data/lib/wice/columns.rb +276 -0
- data/lib/wice/columns/column_action.rb +52 -0
- data/lib/wice/columns/column_boolean.rb +40 -0
- data/lib/wice/columns/column_bootstrap_datepicker.rb +48 -0
- data/lib/wice/columns/column_custom_dropdown.rb +115 -0
- data/lib/wice/columns/column_float.rb +9 -0
- data/lib/wice/columns/column_html5_datepicker.rb +31 -0
- data/lib/wice/columns/column_integer.rb +78 -0
- data/lib/wice/columns/column_jquery_datepicker.rb +49 -0
- data/lib/wice/columns/column_processor_index.rb +23 -0
- data/lib/wice/columns/column_rails_date_helper.rb +41 -0
- data/lib/wice/columns/column_rails_datetime_helper.rb +40 -0
- data/lib/wice/columns/column_range.rb +72 -0
- data/lib/wice/columns/column_string.rb +92 -0
- data/lib/wice/columns/common_date_datetime_mixin.rb +20 -0
- data/lib/wice/columns/common_js_date_datetime_conditions_generator_mixin.rb +42 -0
- data/lib/wice/columns/common_js_date_datetime_mixin.rb +15 -0
- data/lib/wice/columns/common_rails_date_datetime_conditions_generator_mixin.rb +26 -0
- data/lib/wice/columns/common_standard_helper_date_datetime_mixin.rb +22 -0
- data/lib/wice/grid_output_buffer.rb +49 -0
- data/lib/wice/grid_renderer.rb +609 -0
- data/lib/wice/helpers/bs_calendar_helpers.rb +66 -0
- data/lib/wice/helpers/js_calendar_helpers.rb +83 -0
- data/lib/wice/helpers/wice_grid_misc_view_helpers.rb +75 -0
- data/lib/wice/helpers/wice_grid_serialized_queries_view_helpers.rb +95 -0
- data/lib/wice/helpers/wice_grid_view_helpers.rb +718 -0
- data/lib/wice/kaminari_monkey_patching.rb +14 -0
- data/lib/wice/table_column_matrix.rb +65 -0
- data/lib/wice/wice_grid_controller.rb +223 -0
- data/lib/wice/wice_grid_core_ext.rb +142 -0
- data/lib/wice/wice_grid_misc.rb +209 -0
- data/lib/wice/wice_grid_serialized_queries_controller.rb +87 -0
- data/lib/wice/wice_grid_serialized_query.rb +14 -0
- data/lib/wice/wice_grid_spreadsheet.rb +20 -0
- data/lib/wice_grid.rb +676 -0
- data/release_notes/RELEASE_NOTES_3.2.pre1.rdoc +81 -0
- data/release_notes/RELEASE_NOTES_3.2.pre2.rdoc +6 -0
- data/release_notes/RELEASE_NOTES_3.3.0.rdoc +21 -0
- data/spec/schema.rb +9 -0
- data/spec/spec_helper.rb +75 -0
- data/spec/support/active_record.rb +11 -0
- data/spec/support/wice_grid_test_config.rb +175 -0
- data/spec/wice/grid_output_buffer_spec.rb +41 -0
- data/spec/wice/table_column_matrix_spec.rb +38 -0
- data/spec/wice/wice_grid_misc_spec.rb +159 -0
- data/spec/wice/wice_grid_spreadsheet_spec.rb +14 -0
- data/test/readme.txt +1 -0
- data/vendor/assets/javascripts/wice_grid.js +3 -0
- data/vendor/assets/javascripts/wice_grid_init.js.coffee +339 -0
- data/vendor/assets/javascripts/wice_grid_processor.js.coffee +133 -0
- data/vendor/assets/javascripts/wice_grid_saved_queries_init.js.coffee +103 -0
- data/vendor/assets/stylesheets/wice_grid.scss +81 -0
- data/wice_grid.gemspec +36 -0
- metadata +335 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Wice
|
3
|
+
class <<self
|
4
|
+
# Used in routes.rb to define routes to the query processing controller.
|
5
|
+
# Parameters:
|
6
|
+
# * map - the context of the routes execution (instance of <tt>ActionDispatch::Routing::Mapper</tt>).
|
7
|
+
# Normally use +self+ for the first argument: <tt>Wice::define_routes(self, 'queries')</tt>
|
8
|
+
# * controller - name of the query processing controller, i.e. <tt>'queries'</tt> if the controller is +QueriesController+ .
|
9
|
+
# Read section "Saving Queries How-To" in README for more details.
|
10
|
+
def define_routes(map, controller)
|
11
|
+
controller = controller.to_s
|
12
|
+
|
13
|
+
map.post '/wice_grid_serialized_queries/:grid_name',
|
14
|
+
to: "#{controller}#create_saved_query",
|
15
|
+
as: 'create_serialized_query'
|
16
|
+
|
17
|
+
map.post '/wice_grid_serialized_queries/:grid_name/:id',
|
18
|
+
to: "#{controller}#delete_saved_query",
|
19
|
+
as: 'delete_serialized_query'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module SerializedQueriesControllerMixin #:nodoc:
|
24
|
+
def delete_saved_query #:nodoc:
|
25
|
+
init
|
26
|
+
if sq = @query_store_model.find_by_id_and_grid_name(params[:id], @grid_name)
|
27
|
+
if sq.destroy
|
28
|
+
if params[:current]
|
29
|
+
@current = @query_store_model.find_by_id_and_grid_name(params[:current], @grid_name)
|
30
|
+
end
|
31
|
+
@notification_messages = NlMessage['query_deleted_message']
|
32
|
+
else
|
33
|
+
@error_messages = sq.errors.full_raw_messages.join(' ')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
render_asyns_result
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_saved_query #:nodoc:
|
41
|
+
init
|
42
|
+
query_params = if params[@grid_name]
|
43
|
+
params[@grid_name]
|
44
|
+
else
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
query_params.delete(:page)
|
48
|
+
|
49
|
+
@saved_query = @query_store_model.new
|
50
|
+
|
51
|
+
@saved_query.grid_name = @grid_name
|
52
|
+
@saved_query.name = params[:query_name]
|
53
|
+
@saved_query.query = query_params
|
54
|
+
|
55
|
+
@saved_query.attributes = extra unless extra.nil?
|
56
|
+
|
57
|
+
if @saved_query.save
|
58
|
+
@grid_title_id = "#{@grid_name}_title"
|
59
|
+
@notification_messages = NlMessage['query_saved_message']
|
60
|
+
else
|
61
|
+
@error_messages = @saved_query.errors.map { |_, msg| msg }.join(' ')
|
62
|
+
end
|
63
|
+
|
64
|
+
render_asyns_result
|
65
|
+
end
|
66
|
+
|
67
|
+
def extra #:nodoc:
|
68
|
+
params[:extra].permit! unless params[:extra].nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def render_asyns_result #:nodoc:
|
74
|
+
render json: {
|
75
|
+
'error_messages' => @error_messages,
|
76
|
+
'notification_messages' => @notification_messages,
|
77
|
+
'query_list' => render_to_string(inline: '<%=saved_queries_list(@grid_name, @saved_query, controller.extra, @confirm).html_safe%>')
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def init #:nodoc:
|
82
|
+
@query_store_model = ::Wice.get_query_store_model
|
83
|
+
@confirm = params[:confirm] == '1' || params[:confirm] == 'true'
|
84
|
+
@grid_name = params[:grid_name]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class WiceGridSerializedQuery < ActiveRecord::Base #:nodoc:
|
3
|
+
serialize :query
|
4
|
+
|
5
|
+
validates_uniqueness_of :name, scope: :grid_name, on: :create, message: 'A query with this name already exists'
|
6
|
+
|
7
|
+
validates_presence_of :name, message: 'Please submit the name of the custom query'
|
8
|
+
|
9
|
+
# returns a list of all serialized queries
|
10
|
+
def self.list(name, _controller)
|
11
|
+
conditions = { grid_name: name }
|
12
|
+
self.where(conditions).to_a
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'csv'
|
3
|
+
|
4
|
+
module Wice
|
5
|
+
class Spreadsheet #:nodoc:
|
6
|
+
|
7
|
+
#:nodoc:
|
8
|
+
attr_reader :tempfile
|
9
|
+
|
10
|
+
def initialize(name, field_separator, encoding = nil) #:nodoc:
|
11
|
+
@tempfile = Tempfile.new(name)
|
12
|
+
@tempfile.set_encoding(encoding) unless encoding.blank?
|
13
|
+
@csv = CSV.new(@tempfile, col_sep: field_separator)
|
14
|
+
end
|
15
|
+
|
16
|
+
def << (row) #:nodoc:
|
17
|
+
@csv << row
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/wice_grid.rb
ADDED
@@ -0,0 +1,676 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'wice/wice_grid_misc.rb'
|
3
|
+
require 'wice/wice_grid_core_ext.rb'
|
4
|
+
require 'wice/grid_renderer.rb'
|
5
|
+
require 'wice/table_column_matrix.rb'
|
6
|
+
require 'wice/active_record_column_wrapper.rb'
|
7
|
+
require 'wice/helpers/wice_grid_view_helpers.rb'
|
8
|
+
require 'wice/helpers/wice_grid_misc_view_helpers.rb'
|
9
|
+
require 'wice/helpers/wice_grid_serialized_queries_view_helpers.rb'
|
10
|
+
require 'wice/helpers/wice_grid_view_helpers.rb'
|
11
|
+
require 'wice/helpers/bs_calendar_helpers.rb'
|
12
|
+
require 'wice/helpers/js_calendar_helpers.rb'
|
13
|
+
require 'wice/grid_output_buffer.rb'
|
14
|
+
require 'wice/wice_grid_controller.rb'
|
15
|
+
require 'wice/wice_grid_spreadsheet.rb'
|
16
|
+
require 'wice/wice_grid_serialized_queries_controller.rb'
|
17
|
+
require 'wice/columns/column_processor_index.rb'
|
18
|
+
require 'wice/columns.rb'
|
19
|
+
require 'wice/columns/common_date_datetime_mixin.rb'
|
20
|
+
require 'wice/columns/common_standard_helper_date_datetime_mixin.rb'
|
21
|
+
require 'wice/columns/common_js_date_datetime_mixin.rb'
|
22
|
+
require 'wice/columns/common_js_date_datetime_conditions_generator_mixin.rb'
|
23
|
+
require 'wice/columns/common_rails_date_datetime_conditions_generator_mixin.rb'
|
24
|
+
require 'kaminari.rb'
|
25
|
+
|
26
|
+
|
27
|
+
ActionController::Base.send(:helper_method, :wice_grid_custom_filter_params)
|
28
|
+
|
29
|
+
module Wice
|
30
|
+
|
31
|
+
def self.on_action_view_load #:nodoc:
|
32
|
+
::ActionView::Base.class_eval { include Wice::GridViewHelper }
|
33
|
+
[ActionView::Helpers::AssetTagHelper,
|
34
|
+
ActionView::Helpers::TagHelper,
|
35
|
+
ActionView::Helpers::JavaScriptHelper,
|
36
|
+
ActionView::Helpers::FormTagHelper].each do |m|
|
37
|
+
JsCalendarHelpers.send(:include, m)
|
38
|
+
end
|
39
|
+
|
40
|
+
Columns.load_column_processors
|
41
|
+
require 'wice/wice_grid_serialized_query.rb'
|
42
|
+
|
43
|
+
# It is here only because of this: https://github.com/amatsuda/kaminari/pull/267
|
44
|
+
require 'wice/kaminari_monkey_patching.rb'
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
class WiceGridEngine < ::Rails::Engine #:nodoc:
|
49
|
+
initializer 'wice_grid_railtie.configure_rails_initialization' do |_app|
|
50
|
+
ActiveSupport.on_load :action_controller do
|
51
|
+
ActionController::Base.send(:include, Wice::Controller)
|
52
|
+
end
|
53
|
+
|
54
|
+
ActiveSupport.on_load :active_record do
|
55
|
+
ActiveRecord::ConnectionAdapters::Column.send(:include, ::Wice::WiceGridExtentionToActiveRecordColumn)
|
56
|
+
end
|
57
|
+
|
58
|
+
ActiveSupport.on_load :action_view do
|
59
|
+
::Wice.on_action_view_load
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
initializer 'wice_grid_railtie.configure_rails_assets_precompilation' do |app|
|
64
|
+
app.config.assets.precompile << 'icons/grid/*'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Main class responsible for keeping the state of the grid, building an ActiveRelation, and running queries
|
70
|
+
class WiceGrid
|
71
|
+
attr_reader :klass, :name, :resultset, :custom_order, :query_store_model #:nodoc:
|
72
|
+
attr_reader :ar_options, :status, :export_to_csv_enabled, :csv_file_name, :csv_field_separator, :csv_encoding, :saved_query #:nodoc:
|
73
|
+
attr_writer :renderer #:nodoc:
|
74
|
+
attr_accessor :output_buffer, :view_helper_finished, :csv_tempfile #:nodoc:
|
75
|
+
|
76
|
+
# core workflow methods START
|
77
|
+
|
78
|
+
def initialize(klass_or_relation, controller, opts = {}) #:nodoc:
|
79
|
+
@controller = controller
|
80
|
+
|
81
|
+
@relation = klass_or_relation
|
82
|
+
@klass = if @relation.is_a?(Class) && @relation.ancestors.index(ActiveRecord::Base)
|
83
|
+
klass_or_relation
|
84
|
+
else
|
85
|
+
klass_or_relation.klass
|
86
|
+
end
|
87
|
+
|
88
|
+
unless @klass.is_a?(Class) && @klass.ancestors.index(ActiveRecord::Base)
|
89
|
+
fail WiceGridArgumentError.new('ActiveRecord model class (second argument) must be a Class derived from ActiveRecord::Base')
|
90
|
+
end
|
91
|
+
|
92
|
+
# validate :with_resultset & :with_paginated_resultset
|
93
|
+
[:with_resultset, :with_paginated_resultset].each do |callback_symbol|
|
94
|
+
unless [NilClass, Symbol, Proc].index(opts[callback_symbol].class)
|
95
|
+
fail WiceGridArgumentError.new(":#{callback_symbol} must be either a Proc or Symbol object")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
opts[:order_direction].downcase! if opts[:order_direction].is_a?(String)
|
100
|
+
|
101
|
+
# validate :order_direction
|
102
|
+
if opts[:order_direction] && ! (opts[:order_direction] == 'asc' || opts[:order_direction] == :asc || opts[:order_direction] == 'desc' ||
|
103
|
+
opts[:order_direction] == :desc)
|
104
|
+
fail WiceGridArgumentError.new(":order_direction must be either 'asc' or 'desc'.")
|
105
|
+
end
|
106
|
+
|
107
|
+
begin
|
108
|
+
# options that are understood
|
109
|
+
@options = {
|
110
|
+
conditions: nil,
|
111
|
+
csv_file_name: nil,
|
112
|
+
csv_field_separator: ConfigurationProvider.value_for(:CSV_FIELD_SEPARATOR),
|
113
|
+
csv_encoding: ConfigurationProvider.value_for(:CSV_ENCODING),
|
114
|
+
custom_order: {},
|
115
|
+
enable_export_to_csv: ConfigurationProvider.value_for(:ENABLE_EXPORT_TO_CSV),
|
116
|
+
group: nil,
|
117
|
+
include: nil,
|
118
|
+
joins: nil,
|
119
|
+
name: ConfigurationProvider.value_for(:GRID_NAME),
|
120
|
+
order: nil,
|
121
|
+
order_direction: ConfigurationProvider.value_for(:ORDER_DIRECTION),
|
122
|
+
page: 1,
|
123
|
+
page_method_name: ConfigurationProvider.value_for(:PAGE_METHOD_NAME),
|
124
|
+
per_page: ConfigurationProvider.value_for(:PER_PAGE),
|
125
|
+
saved_query: nil,
|
126
|
+
with_paginated_resultset: nil,
|
127
|
+
with_resultset: nil,
|
128
|
+
use_default_scope: ConfigurationProvider.value_for(:USE_DEFAULT_SCOPE)
|
129
|
+
}
|
130
|
+
rescue NameError
|
131
|
+
raise NameError.new('A constant is missing in wice_grid_config.rb: ' + $ERROR_INFO.message +
|
132
|
+
'. This can happen when you upgrade the WiceGrid to a newer version with a new configuration constant. ' \
|
133
|
+
'Add the constant manually or re-run `bundle exec rails g wice_grid:install`.')
|
134
|
+
end
|
135
|
+
# validate parameters
|
136
|
+
opts.assert_valid_keys(@options.keys)
|
137
|
+
|
138
|
+
@options.merge!(opts)
|
139
|
+
@export_to_csv_enabled = @options[:enable_export_to_csv]
|
140
|
+
@csv_file_name = @options[:csv_file_name]
|
141
|
+
@csv_field_separator = @options[:csv_field_separator]
|
142
|
+
@csv_encoding = @options[:csv_encoding]
|
143
|
+
|
144
|
+
case @name = @options[:name]
|
145
|
+
when String
|
146
|
+
when Symbol
|
147
|
+
@name = @name.to_s
|
148
|
+
else
|
149
|
+
fail WiceGridArgumentError.new('name of the grid should be a string or a symbol')
|
150
|
+
end
|
151
|
+
fail WiceGridArgumentError.new('name of the grid can only contain alphanumeruc characters') unless @name =~ /^[a-zA-Z\d_]*$/
|
152
|
+
|
153
|
+
@table_column_matrix = TableColumnMatrix.new
|
154
|
+
@table_column_matrix.default_model_class = @klass
|
155
|
+
|
156
|
+
@ar_options = {}
|
157
|
+
@status = HashWithIndifferentAccess.new
|
158
|
+
|
159
|
+
if @options[:order]
|
160
|
+
@options[:order] = @options[:order].to_s
|
161
|
+
@options[:order_direction] = @options[:order_direction].to_s
|
162
|
+
|
163
|
+
@status[:order_direction] = @options[:order_direction]
|
164
|
+
@status[:order] = @options[:order]
|
165
|
+
|
166
|
+
end
|
167
|
+
@status[:per_page] = @options[:per_page]
|
168
|
+
@status[:page] = @options[:page]
|
169
|
+
@status[:conditions] = @options[:conditions]
|
170
|
+
@status[:f] = @options[:f]
|
171
|
+
|
172
|
+
process_loading_query
|
173
|
+
process_params
|
174
|
+
|
175
|
+
@ar_options_formed = false
|
176
|
+
end
|
177
|
+
|
178
|
+
# A block executed from within the plugin to process records of the current page.
|
179
|
+
# The argument to the callback is the array of the records. See the README for more details.
|
180
|
+
def with_paginated_resultset(&callback)
|
181
|
+
@options[:with_paginated_resultset] = callback
|
182
|
+
end
|
183
|
+
|
184
|
+
# A block executed from within the plugin to process all records browsable through
|
185
|
+
# all pages with the current filters. The argument to
|
186
|
+
# the callback is a lambda object which returns the list of records when called. See the README for the explanation.
|
187
|
+
def with_resultset(&callback)
|
188
|
+
@options[:with_resultset] = callback
|
189
|
+
end
|
190
|
+
|
191
|
+
def process_loading_query #:nodoc:
|
192
|
+
@saved_query = nil
|
193
|
+
if params[name] && params[name][:q]
|
194
|
+
@saved_query = load_query(params[name][:q])
|
195
|
+
params[name].delete(:q)
|
196
|
+
elsif @options[:saved_query]
|
197
|
+
if @options[:saved_query].is_a? ActiveRecord::Base
|
198
|
+
@saved_query = @options[:saved_query]
|
199
|
+
else
|
200
|
+
@saved_query = load_query(@options[:saved_query])
|
201
|
+
end
|
202
|
+
else
|
203
|
+
return
|
204
|
+
end
|
205
|
+
|
206
|
+
unless @saved_query.nil?
|
207
|
+
params[name] = HashWithIndifferentAccess.new if params[name].blank?
|
208
|
+
[:f, :order, :order_direction].each do |key|
|
209
|
+
if @saved_query.query[key].blank?
|
210
|
+
params[name].delete(key)
|
211
|
+
else
|
212
|
+
params[name][key] = @saved_query.query[key]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def process_params #:nodoc:
|
219
|
+
if this_grid_params
|
220
|
+
@status.merge!(this_grid_params)
|
221
|
+
@status.delete(:export) unless self.export_to_csv_enabled
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# declare_column(String, ActiveRecord, CustomFilterSpec, nil | string, nil | Boolean)
|
226
|
+
def declare_column(
|
227
|
+
column_name: nil,
|
228
|
+
model: nil,
|
229
|
+
custom_filter_active: nil,
|
230
|
+
table_alias: nil,
|
231
|
+
filter_type: nil,
|
232
|
+
assocs: []) #:nodoc:
|
233
|
+
|
234
|
+
|
235
|
+
@options[:include] = Wice.build_includes(@options[:include], assocs)
|
236
|
+
|
237
|
+
if model # this is an included table
|
238
|
+
column = @table_column_matrix.get_column_by_model_class_and_column_name(model, column_name)
|
239
|
+
fail WiceGridArgumentError.new("Column '#{column_name}' is not found in table '#{model.table_name}'!") if column.nil?
|
240
|
+
main_table = false
|
241
|
+
table_name = model.table_name
|
242
|
+
else
|
243
|
+
column = @table_column_matrix.get_column_in_default_model_class_by_column_name(column_name)
|
244
|
+
if column.nil?
|
245
|
+
fail WiceGridArgumentError.new("Column '#{column_name}' is not found in table '#{@klass.table_name}'! " \
|
246
|
+
"If '#{column_name}' belongs to another table you should declare it in :include or :join when initialising " \
|
247
|
+
'the grid, and specify :model in column declaration.')
|
248
|
+
end
|
249
|
+
main_table = true
|
250
|
+
table_name = @table_column_matrix.default_model_class.table_name
|
251
|
+
end
|
252
|
+
|
253
|
+
if column
|
254
|
+
conditions_generator = ActiveRecordColumnWrapper.new(column, @status[:f], main_table, table_alias, custom_filter_active, filter_type)
|
255
|
+
conditions, current_parameter_name = conditions_generator.wg_initialize_request_parameters
|
256
|
+
|
257
|
+
if @status[:f] && conditions.blank?
|
258
|
+
@status[:f].delete(current_parameter_name)
|
259
|
+
end
|
260
|
+
|
261
|
+
@table_column_matrix.add_condition(column, conditions)
|
262
|
+
|
263
|
+
# [ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::Column, String, Boolean]
|
264
|
+
[column, table_name, main_table]
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def form_ar_options(opts = {}) #:nodoc:
|
269
|
+
return if @ar_options_formed
|
270
|
+
@ar_options_formed = true unless opts[:forget_generated_options]
|
271
|
+
|
272
|
+
# validate @status[:order_direction]
|
273
|
+
@status[:order_direction] = case @status[:order_direction]
|
274
|
+
when /desc/i
|
275
|
+
'desc'
|
276
|
+
when /asc/i
|
277
|
+
'asc'
|
278
|
+
else
|
279
|
+
''
|
280
|
+
end
|
281
|
+
|
282
|
+
# conditions
|
283
|
+
# do not delete for a while
|
284
|
+
# https://github.com/leikind/wice_grid/issues/144
|
285
|
+
# if @table_column_matrix.generated_conditions.size == 0
|
286
|
+
# @status.delete(:f)
|
287
|
+
# end
|
288
|
+
|
289
|
+
initial_conditions_active_relation = @klass.where(@status[:conditions])
|
290
|
+
|
291
|
+
@ar_options[:conditions] =
|
292
|
+
@table_column_matrix.conditions.reduce(initial_conditions_active_relation) do |active_relation_accu, cond|
|
293
|
+
conditions_active_relation = @klass.where(cond)
|
294
|
+
active_relation_accu.merge(conditions_active_relation)
|
295
|
+
end
|
296
|
+
|
297
|
+
# conditions processed
|
298
|
+
|
299
|
+
if (!opts[:skip_ordering]) && ! @status[:order].blank?
|
300
|
+
@ar_options[:order] = add_custom_order_sql(complete_column_name(@status[:order]))
|
301
|
+
|
302
|
+
@ar_options[:order] += ' ' + @status[:order_direction]
|
303
|
+
end
|
304
|
+
|
305
|
+
@ar_options[:joins] = @options[:joins]
|
306
|
+
@ar_options[:include] = @options[:include]
|
307
|
+
@ar_options[:group] = @options[:group]
|
308
|
+
|
309
|
+
if self.output_html?
|
310
|
+
@ar_options[:per_page] = @status[:per_page]
|
311
|
+
@ar_options[:page] = @status[:page]
|
312
|
+
|
313
|
+
if (show_all_limit = Wice::ConfigurationProvider.value_for(:SHOW_ALL_ALLOWED_UP_TO, strict: false)) && all_record_mode?
|
314
|
+
if do_count > show_all_limit # force-reset SHOW-ALL to pagination
|
315
|
+
@status[:pp] = nil
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def add_references(relation) #:nodoc:
|
323
|
+
if @ar_options[:include] && relation.respond_to?(:references)
|
324
|
+
# refs = [@ar_options[:include]] unless @ar_options[:include].is_a?(Array)
|
325
|
+
relation = relation.references(* @ar_options[:include])
|
326
|
+
end
|
327
|
+
relation
|
328
|
+
end
|
329
|
+
|
330
|
+
# TO DO: what to do with other @ar_options values?
|
331
|
+
def read #:nodoc:
|
332
|
+
form_ar_options
|
333
|
+
use_default_or_unscoped do
|
334
|
+
@resultset = if self.output_csv? || all_record_mode?
|
335
|
+
relation = @relation
|
336
|
+
.includes(@ar_options[:include])
|
337
|
+
.joins(@ar_options[:joins])
|
338
|
+
.order(@ar_options[:order])
|
339
|
+
.group(@ar_options[:group])
|
340
|
+
.merge(@ar_options[:conditions])
|
341
|
+
relation = add_references relation
|
342
|
+
|
343
|
+
relation
|
344
|
+
else
|
345
|
+
# p @ar_options
|
346
|
+
relation = @relation
|
347
|
+
.send(@options[:page_method_name], @ar_options[:page])
|
348
|
+
.per(@ar_options[:per_page])
|
349
|
+
.includes(@ar_options[:include])
|
350
|
+
.joins(@ar_options[:joins])
|
351
|
+
.order(@ar_options[:order])
|
352
|
+
.group(@ar_options[:group])
|
353
|
+
.merge(@ar_options[:conditions])
|
354
|
+
|
355
|
+
relation = add_references relation
|
356
|
+
|
357
|
+
relation
|
358
|
+
end
|
359
|
+
end
|
360
|
+
invoke_resultset_callbacks
|
361
|
+
end
|
362
|
+
|
363
|
+
# core workflow methods END
|
364
|
+
|
365
|
+
# Getters
|
366
|
+
|
367
|
+
def filter_params(view_column) #:nodoc:
|
368
|
+
column_name = view_column.attribute_name_fully_qualified_for_all_but_main_table_columns
|
369
|
+
if @status[:f] && @status[:f][column_name]
|
370
|
+
@status[:f][column_name]
|
371
|
+
else
|
372
|
+
{}
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def resultset #:nodoc:
|
377
|
+
self.read unless @resultset # database querying is late!
|
378
|
+
@resultset
|
379
|
+
end
|
380
|
+
|
381
|
+
def each #:nodoc:
|
382
|
+
self.read unless @resultset # database querying is late!
|
383
|
+
@resultset.each do |r|
|
384
|
+
yield r
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def ordered_by?(column) #:nodoc:
|
389
|
+
return nil if @status[:order].blank?
|
390
|
+
if column.main_table && ! @status[:order].index('.')
|
391
|
+
@status[:order] == column.attribute
|
392
|
+
else
|
393
|
+
@status[:order] == column.table_alias_or_table_name + '.' + column.attribute
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
def ordered_by #:nodoc:
|
398
|
+
@status[:order]
|
399
|
+
end
|
400
|
+
|
401
|
+
def order_direction #:nodoc:
|
402
|
+
@status[:order_direction]
|
403
|
+
end
|
404
|
+
|
405
|
+
def filtering_on? #:nodoc:
|
406
|
+
!@status[:f].blank?
|
407
|
+
end
|
408
|
+
|
409
|
+
def filtered_by #:nodoc:
|
410
|
+
@status[:f].nil? ? [] : @status[:f].keys
|
411
|
+
end
|
412
|
+
|
413
|
+
def filtered_by?(view_column) #:nodoc:
|
414
|
+
@status[:f].nil? ? false : @status[:f].key?(view_column.attribute_name_fully_qualified_for_all_but_main_table_columns)
|
415
|
+
end
|
416
|
+
|
417
|
+
def get_state_as_parameter_value_pairs(including_saved_query_request = false) #:nodoc:
|
418
|
+
res = []
|
419
|
+
unless status[:f].blank?
|
420
|
+
Wice::WgHash.parameter_names_and_values(status[:f], [name, 'f']).collect do |param_name, value|
|
421
|
+
if value.is_a?(Array)
|
422
|
+
param_name_ar = param_name + '[]'
|
423
|
+
value.each do |v|
|
424
|
+
res << [param_name_ar, v]
|
425
|
+
end
|
426
|
+
else
|
427
|
+
res << [param_name, value]
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
if including_saved_query_request && @saved_query
|
433
|
+
res << ["#{name}[q]", @saved_query.id]
|
434
|
+
end
|
435
|
+
|
436
|
+
[:order, :order_direction].select do|parameter|
|
437
|
+
status[parameter]
|
438
|
+
end.collect do |parameter|
|
439
|
+
res << ["#{name}[#{parameter}]", status[parameter]]
|
440
|
+
end
|
441
|
+
|
442
|
+
res
|
443
|
+
end
|
444
|
+
|
445
|
+
def count #:nodoc:
|
446
|
+
form_ar_options(skip_ordering: true, forget_generated_options: true)
|
447
|
+
do_count
|
448
|
+
end
|
449
|
+
|
450
|
+
def do_count #:nodoc:
|
451
|
+
@relation
|
452
|
+
.all
|
453
|
+
.merge(@ar_options[:conditions]).count(
|
454
|
+
joins: @ar_options[:joins],
|
455
|
+
include: @ar_options[:include],
|
456
|
+
group: @ar_options[:group]
|
457
|
+
)
|
458
|
+
end
|
459
|
+
|
460
|
+
alias_method :size, :count
|
461
|
+
|
462
|
+
def empty? #:nodoc:
|
463
|
+
self.count == 0
|
464
|
+
end
|
465
|
+
|
466
|
+
# with this variant we get even those values which do not appear in the resultset
|
467
|
+
def distinct_values_for_column(column) #:nodoc:
|
468
|
+
column.model.select("distinct #{column.name}").order("#{column.name} asc").collect do|ar|
|
469
|
+
ar[column.name]
|
470
|
+
end.reject(&:blank?).map { |i| [i, i] }
|
471
|
+
end
|
472
|
+
|
473
|
+
def distinct_values_for_column_in_resultset(messages) #:nodoc:
|
474
|
+
uniq_vals = Set.new
|
475
|
+
|
476
|
+
resultset_without_paging_without_user_filters.each do |ar|
|
477
|
+
v = ar.deep_send(*messages)
|
478
|
+
uniq_vals << v unless v.nil?
|
479
|
+
end
|
480
|
+
uniq_vals.to_a.map do|i|
|
481
|
+
if i.is_a?(Array) && i.size == 2
|
482
|
+
i
|
483
|
+
elsif i.is_a?(Hash) && i.size == 1
|
484
|
+
i.to_a.flatten
|
485
|
+
else
|
486
|
+
[i, i]
|
487
|
+
end
|
488
|
+
end.sort { |a, b| a[0] <=> b[0] }
|
489
|
+
end
|
490
|
+
|
491
|
+
def output_csv? #:nodoc:
|
492
|
+
@status[:export] == 'csv'
|
493
|
+
end
|
494
|
+
|
495
|
+
def output_html? #:nodoc:
|
496
|
+
@status[:export].blank?
|
497
|
+
end
|
498
|
+
|
499
|
+
def all_record_mode? #:nodoc:
|
500
|
+
@status[:pp]
|
501
|
+
end
|
502
|
+
|
503
|
+
def dump_status #:nodoc:
|
504
|
+
" params: #{params[name].inspect}\n" + " status: #{@status.inspect}\n" \
|
505
|
+
" ar_options #{@ar_options.inspect}\n"
|
506
|
+
end
|
507
|
+
|
508
|
+
# Returns the list of objects browsable through all pages with the current filters.
|
509
|
+
# Should only be called after the +grid+ helper.
|
510
|
+
def all_pages_records
|
511
|
+
fail WiceGridException.new('all_pages_records can only be called only after the grid view helper') unless self.view_helper_finished
|
512
|
+
resultset_without_paging_with_user_filters
|
513
|
+
end
|
514
|
+
|
515
|
+
# Returns the list of objects displayed on current page. Should only be called after the +grid+ helper.
|
516
|
+
def current_page_records
|
517
|
+
fail WiceGridException.new('current_page_records can only be called only after the grid view helper') unless self.view_helper_finished
|
518
|
+
@resultset
|
519
|
+
end
|
520
|
+
|
521
|
+
protected
|
522
|
+
|
523
|
+
def invoke_resultset_callback(callback, argument) #:nodoc:
|
524
|
+
case callback
|
525
|
+
when Proc
|
526
|
+
callback.call(argument)
|
527
|
+
when Symbol
|
528
|
+
@controller.send(callback, argument)
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
def invoke_resultset_callbacks #:nodoc:
|
533
|
+
invoke_resultset_callback(@options[:with_paginated_resultset], @resultset)
|
534
|
+
invoke_resultset_callback(@options[:with_resultset], self.active_relation_for_resultset_without_paging_with_user_filters)
|
535
|
+
end
|
536
|
+
|
537
|
+
def add_custom_order_sql(fully_qualified_column_name) #:nodoc:
|
538
|
+
custom_order = if @options[:custom_order].key?(fully_qualified_column_name)
|
539
|
+
@options[:custom_order][fully_qualified_column_name]
|
540
|
+
else
|
541
|
+
if view_column = @renderer[fully_qualified_column_name]
|
542
|
+
view_column.custom_order
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
if custom_order.blank?
|
547
|
+
sqlite = ActiveRecord::ConnectionAdapters.const_defined?(:SQLite3Adapter) && ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
|
548
|
+
postgres = ActiveRecord::ConnectionAdapters.const_defined?(:PostgreSQLAdapter) && ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
549
|
+
if sqlite || postgres
|
550
|
+
fully_qualified_column_name.strip.split('.').map { |chunk| ActiveRecord::Base.connection.quote_table_name(chunk) }.join('.')
|
551
|
+
else
|
552
|
+
ActiveRecord::Base.connection.quote_table_name(fully_qualified_column_name.strip)
|
553
|
+
end
|
554
|
+
else
|
555
|
+
if custom_order.is_a? String
|
556
|
+
custom_order.gsub(/\?/, fully_qualified_column_name)
|
557
|
+
elsif custom_order.is_a? Proc
|
558
|
+
custom_order.call(fully_qualified_column_name)
|
559
|
+
else
|
560
|
+
fail WiceGridArgumentError.new("invalid custom order #{custom_order.inspect}")
|
561
|
+
end
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
def complete_column_name(col_name) #:nodoc:
|
566
|
+
if col_name.index('.') # already has a table name
|
567
|
+
col_name
|
568
|
+
else # add the default table
|
569
|
+
"#{@klass.table_name}.#{col_name}"
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
def params #:nodoc:
|
574
|
+
@controller.params
|
575
|
+
end
|
576
|
+
|
577
|
+
def this_grid_params #:nodoc:
|
578
|
+
params[name]
|
579
|
+
end
|
580
|
+
|
581
|
+
def resultset_without_paging_without_user_filters #:nodoc:
|
582
|
+
form_ar_options
|
583
|
+
|
584
|
+
use_default_or_unscoped do
|
585
|
+
relation = @relation.joins(@ar_options[:joins])
|
586
|
+
.includes(@ar_options[:include])
|
587
|
+
.group(@ar_options[:group])
|
588
|
+
.where(@options[:conditions])
|
589
|
+
|
590
|
+
relation = add_references relation
|
591
|
+
|
592
|
+
relation
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
# not used right now
|
597
|
+
# def count_resultset_without_paging_without_user_filters #:nodoc:
|
598
|
+
# form_ar_options
|
599
|
+
# @klass.unscoped do
|
600
|
+
# @relation.count(
|
601
|
+
# joins: @ar_options[:joins],
|
602
|
+
# include: @ar_options[:include],
|
603
|
+
# group: @ar_options[:group],
|
604
|
+
# conditions: @options[:conditions]
|
605
|
+
# )
|
606
|
+
# end
|
607
|
+
# end
|
608
|
+
|
609
|
+
def resultset_without_paging_with_user_filters #:nodoc:
|
610
|
+
active_relation_for_resultset_without_paging_with_user_filters.to_a
|
611
|
+
end
|
612
|
+
|
613
|
+
def active_relation_for_resultset_without_paging_with_user_filters #:nodoc:
|
614
|
+
form_ar_options
|
615
|
+
relation = nil
|
616
|
+
|
617
|
+
use_default_or_unscoped do
|
618
|
+
relation = @relation
|
619
|
+
.joins(@ar_options[:joins])
|
620
|
+
.includes(@ar_options[:include])
|
621
|
+
.order(@ar_options[:order])
|
622
|
+
.merge(@ar_options[:conditions])
|
623
|
+
|
624
|
+
relation = add_references relation
|
625
|
+
end
|
626
|
+
relation
|
627
|
+
end
|
628
|
+
|
629
|
+
def load_query(query_id) #:nodoc:
|
630
|
+
@query_store_model ||= Wice.get_query_store_model
|
631
|
+
query = @query_store_model.find_by_id_and_grid_name(query_id, self.name)
|
632
|
+
Wice.log("Query with id #{query_id} for grid '#{self.name}' not found!!!") if query.nil?
|
633
|
+
query
|
634
|
+
end
|
635
|
+
|
636
|
+
def use_default_or_unscoped #:nodoc:
|
637
|
+
if @options[:use_default_scope]
|
638
|
+
yield
|
639
|
+
else
|
640
|
+
@klass.unscoped { yield }
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
end
|
645
|
+
|
646
|
+
# routines called from WiceGridExtentionToActiveRecordColumn (ActiveRecord::ConnectionAdapters::Column) or ConditionsGeneratorColumn classes
|
647
|
+
module GridTools #:nodoc:
|
648
|
+
class << self
|
649
|
+
def special_value(str) #:nodoc:
|
650
|
+
str =~ /^\s*(not\s+)?null\s*$/i
|
651
|
+
end
|
652
|
+
|
653
|
+
# create a Time instance out of parameters
|
654
|
+
def params_2_datetime(par) #:nodoc:
|
655
|
+
return nil if par.blank?
|
656
|
+
params = [par[:year], par[:month], par[:day], par[:hour], par[:minute]].collect { |v| v.blank? ? nil : v.to_i }
|
657
|
+
begin
|
658
|
+
Time.local(*params)
|
659
|
+
rescue ArgumentError, TypeError
|
660
|
+
nil
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
664
|
+
# create a Date instance out of parameters
|
665
|
+
def params_2_date(par) #:nodoc:
|
666
|
+
return nil if par.blank?
|
667
|
+
params = [par[:year], par[:month], par[:day]].collect { |v| v.blank? ? nil : v.to_i }
|
668
|
+
begin
|
669
|
+
Date.civil(*params)
|
670
|
+
rescue ArgumentError, TypeError
|
671
|
+
nil
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|
675
|
+
end
|
676
|
+
end
|