active_scaffold 3.5.2 → 3.6.0.rc1
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 +4 -4
- data/{CHANGELOG → CHANGELOG.rdoc} +66 -0
- data/README.md +17 -7
- data/app/assets/javascripts/active_scaffold.js.erb +0 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +63 -6
- data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
- data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
- data/app/views/active_scaffold_overrides/_base_form.html.erb +2 -2
- data/app/views/active_scaffold_overrides/_form.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +3 -2
- data/app/views/active_scaffold_overrides/_form_association_record.html.erb +6 -6
- data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_list.html.erb +2 -1
- data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
- data/app/views/active_scaffold_overrides/_list_messages.html.erb +1 -0
- data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
- data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_messages.html.erb +1 -0
- data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
- data/app/views/active_scaffold_overrides/_render_field.js.erb +2 -1
- data/app/views/active_scaffold_overrides/_show_association_horizontal.html.erb +2 -1
- data/app/views/active_scaffold_overrides/_show_columns.html.erb +2 -2
- data/app/views/active_scaffold_overrides/_show_horizontal_record.html.erb +4 -4
- data/app/views/active_scaffold_overrides/_update_calculations.js.erb +1 -1
- data/app/views/active_scaffold_overrides/_update_column.js.erb +2 -2
- data/app/views/active_scaffold_overrides/action_confirmation.html.erb +2 -2
- data/app/views/active_scaffold_overrides/delete.html.erb +2 -2
- data/app/views/active_scaffold_overrides/on_action_update.js.erb +16 -6
- data/app/views/active_scaffold_overrides/on_update.js.erb +1 -1
- data/app/views/active_scaffold_overrides/row.js.erb +1 -1
- data/app/views/active_scaffold_overrides/update_column.js.erb +1 -1
- data/config/locales/de.yml +2 -1
- data/config/locales/en.yml +1 -0
- data/config/locales/es.yml +1 -0
- data/config/locales/fr.yml +2 -1
- data/config/locales/hu.yml +1 -0
- data/config/locales/ja.yml +1 -0
- data/config/locales/ru.yml +1 -0
- data/lib/active_scaffold.rb +19 -16
- data/lib/active_scaffold/actions/common_search.rb +11 -8
- data/lib/active_scaffold/actions/core.rb +89 -71
- data/lib/active_scaffold/actions/create.rb +28 -28
- data/lib/active_scaffold/actions/delete.rb +3 -3
- data/lib/active_scaffold/actions/field_search.rb +53 -43
- data/lib/active_scaffold/actions/list.rb +111 -27
- data/lib/active_scaffold/actions/nested.rb +65 -48
- data/lib/active_scaffold/actions/search.rb +1 -1
- data/lib/active_scaffold/actions/show.rb +4 -4
- data/lib/active_scaffold/actions/subform.rb +12 -17
- data/lib/active_scaffold/actions/update.rb +96 -77
- data/lib/active_scaffold/active_record_permissions.rb +2 -11
- data/lib/active_scaffold/attribute_params.rb +104 -86
- data/lib/active_scaffold/bridges.rb +8 -8
- data/lib/active_scaffold/bridges/active_storage.rb +6 -0
- data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +33 -0
- data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
- data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
- data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
- data/lib/active_scaffold/bridges/bitfields.rb +1 -0
- data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
- data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -12
- data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
- data/lib/active_scaffold/bridges/chosen/helpers.rb +11 -9
- data/lib/active_scaffold/bridges/date_picker/ext.rb +0 -13
- data/lib/active_scaffold/bridges/date_picker/helper.rb +49 -44
- data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +3 -3
- data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
- data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +10 -7
- data/lib/active_scaffold/bridges/paper_trail.rb +1 -1
- data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
- data/lib/active_scaffold/bridges/record_select/helpers.rb +12 -16
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -19
- data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
- data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +21 -4
- data/lib/active_scaffold/config/base.rb +133 -41
- data/lib/active_scaffold/config/core.rb +146 -18
- data/lib/active_scaffold/config/delete.rb +14 -1
- data/lib/active_scaffold/config/field_search.rb +7 -1
- data/lib/active_scaffold/config/form.rb +10 -1
- data/lib/active_scaffold/config/list.rb +39 -13
- data/lib/active_scaffold/config/mark.rb +4 -2
- data/lib/active_scaffold/config/nested.rb +16 -17
- data/lib/active_scaffold/config/search.rb +9 -0
- data/lib/active_scaffold/config/show.rb +4 -0
- data/lib/active_scaffold/config/update.rb +4 -0
- data/lib/active_scaffold/configurable.rb +14 -7
- data/lib/active_scaffold/constraints.rb +22 -20
- data/lib/active_scaffold/core.rb +68 -29
- data/lib/active_scaffold/data_structures/action_columns.rb +50 -59
- data/lib/active_scaffold/data_structures/action_link.rb +50 -20
- data/lib/active_scaffold/data_structures/action_links.rb +15 -13
- data/lib/active_scaffold/data_structures/association/abstract.rb +41 -15
- data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
- data/lib/active_scaffold/data_structures/association/active_record.rb +6 -2
- data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
- data/lib/active_scaffold/data_structures/column.rb +75 -66
- data/lib/active_scaffold/data_structures/columns.rb +3 -2
- data/lib/active_scaffold/data_structures/nested_info.rb +21 -19
- data/lib/active_scaffold/data_structures/set.rb +8 -0
- data/lib/active_scaffold/data_structures/sorting.rb +10 -2
- data/lib/active_scaffold/delayed_setup.rb +16 -5
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +3 -2
- data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
- data/lib/active_scaffold/extensions/cow_proxy.rb +91 -0
- data/lib/active_scaffold/extensions/ice_nine.rb +36 -0
- data/lib/active_scaffold/extensions/left_outer_joins.rb +8 -33
- data/lib/active_scaffold/extensions/localize.rb +3 -1
- data/lib/active_scaffold/extensions/routing_mapper.rb +6 -45
- data/lib/active_scaffold/extensions/to_label.rb +3 -2
- data/lib/active_scaffold/extensions/unsaved_record.rb +2 -4
- data/lib/active_scaffold/finder.rb +104 -73
- data/lib/active_scaffold/helpers/action_link_helpers.rb +62 -36
- data/lib/active_scaffold/helpers/association_helpers.rb +21 -19
- data/lib/active_scaffold/helpers/controller_helpers.rb +23 -10
- data/lib/active_scaffold/helpers/form_column_helpers.rb +157 -121
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
- data/lib/active_scaffold/helpers/id_helpers.rb +6 -2
- data/lib/active_scaffold/helpers/list_column_helpers.rb +82 -53
- data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
- data/lib/active_scaffold/helpers/search_column_helpers.rb +29 -34
- data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
- data/lib/active_scaffold/helpers/view_helpers.rb +38 -35
- data/lib/active_scaffold/marked_model.rb +2 -2
- data/lib/active_scaffold/orm_checks.rb +3 -7
- data/lib/active_scaffold/paginator.rb +7 -7
- data/lib/active_scaffold/registry.rb +33 -0
- data/lib/active_scaffold/responds_to_parent.rb +8 -11
- data/lib/active_scaffold/tableless.rb +67 -65
- data/lib/active_scaffold/version.rb +2 -2
- data/lib/generators/active_scaffold/controller_generator.rb +2 -2
- data/lib/generators/active_scaffold/install_generator.rb +1 -1
- data/lib/generators/active_scaffold/resource_generator.rb +2 -2
- data/shoulda_macros/macros.rb +3 -1
- data/test/bridges/date_picker_test.rb +1 -2
- data/test/bridges/paperclip_test.rb +6 -6
- data/test/class_with_finder.rb +2 -2
- data/test/company.rb +4 -4
- data/test/config/create_test.rb +4 -2
- data/test/config/nested_test.rb +1 -1
- data/test/config/show_test.rb +1 -1
- data/test/config/update_test.rb +7 -6
- data/test/data_structures/action_columns_test.rb +2 -2
- data/test/data_structures/action_links_test.rb +1 -1
- data/test/data_structures/column_test.rb +3 -6
- data/test/data_structures/columns_test.rb +2 -2
- data/test/data_structures/sorting_test.rb +7 -0
- data/test/extensions/active_record_test.rb +4 -4
- data/test/extensions/routing_mapper_test.rb +2 -2
- data/test/helpers/list_column_helpers_test.rb +3 -1
- data/test/misc/active_record_permissions_test.rb +3 -11
- data/test/misc/attribute_params_test.rb +12 -8
- data/test/misc/calculation_test.rb +1 -1
- data/test/misc/configurable_test.rb +10 -10
- data/test/misc/constraints_test.rb +2 -2
- data/test/misc/convert_numbers_format_test.rb +7 -3
- data/test/misc/lang_test.rb +1 -1
- data/test/misc/parse_datetime_test.rb +3 -4
- data/test/misc/tableless_test.rb +6 -0
- data/test/mock_app/Rakefile +1 -1
- data/test/mock_app/app/assets/config/manifest.js +0 -0
- data/test/mock_app/app/controllers/cars_controller.rb +1 -0
- data/test/mock_app/app/controllers/people_controller.rb +3 -1
- data/test/mock_app/config/application.rb +2 -1
- data/test/mock_app/config/boot.rb +1 -1
- data/test/mock_app/config/environment.rb +2 -2
- data/test/mock_app/config/routes.rb +4 -1
- data/test/mock_app/db/schema.rb +2 -0
- data/test/performance/list_cars_performance_test.rb +34 -0
- data/test/performance/list_people_performance_test.rb +31 -0
- data/test/performance_test_help.rb +3 -0
- data/test/test_helper.rb +10 -2
- metadata +56 -15
- data/app/assets/javascripts/prototype/rico_corner.js +0 -370
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -7
@@ -1,7 +1,9 @@
|
|
1
1
|
class Object
|
2
2
|
def as_(key, options = {})
|
3
3
|
if key.present?
|
4
|
-
|
4
|
+
scope = [:active_scaffold, *options.delete(:scope)]
|
5
|
+
options = options.reverse_merge(:scope => scope, :default => key.is_a?(String) ? key : key.to_s.titleize)
|
6
|
+
text = I18n.translate(key.to_s, options).html_safe # rubocop:disable Rails/OutputSafety
|
5
7
|
# text = nil if text.include?('translation missing:')
|
6
8
|
end
|
7
9
|
text || key
|
@@ -16,9 +16,9 @@ module ActiveScaffold
|
|
16
16
|
|
17
17
|
def get_actions(actions_hash, options)
|
18
18
|
default_actions = default_actions(actions_hash)
|
19
|
-
if only = options[:only]
|
19
|
+
if (only = options[:only])
|
20
20
|
Array(only).map(&:to_sym)
|
21
|
-
elsif except = options[:except]
|
21
|
+
elsif (except = options[:except])
|
22
22
|
default_actions - Array(except).map(&:to_sym)
|
23
23
|
else
|
24
24
|
default_actions
|
@@ -29,13 +29,13 @@ module ActiveScaffold
|
|
29
29
|
actions = get_actions(ACTIVE_SCAFFOLD_ASSOCIATION_ROUTING, options)
|
30
30
|
|
31
31
|
mapper.collection do
|
32
|
-
|
32
|
+
ActiveScaffold::Routing::ACTIVE_SCAFFOLD_ASSOCIATION_ROUTING[:collection].each do |name, type|
|
33
33
|
mapper.match(name, via: type) if actions.include? name
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
mapper.member do
|
38
|
-
|
38
|
+
ActiveScaffold::Routing::ACTIVE_SCAFFOLD_ASSOCIATION_ROUTING[:member].each do |name, type|
|
39
39
|
mapper.match(name, via: type) if actions.include? name
|
40
40
|
end
|
41
41
|
end
|
@@ -52,13 +52,13 @@ module ActiveScaffold
|
|
52
52
|
actions = get_actions(ACTIVE_SCAFFOLD_CORE_ROUTING, options)
|
53
53
|
|
54
54
|
mapper.collection do
|
55
|
-
|
55
|
+
ActiveScaffold::Routing::ACTIVE_SCAFFOLD_CORE_ROUTING[:collection].each do |name, type|
|
56
56
|
mapper.match(name, via: type) if actions.include? name
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
60
|
mapper.member do
|
61
|
-
|
61
|
+
ActiveScaffold::Routing::ACTIVE_SCAFFOLD_CORE_ROUTING[:member].each do |name, type|
|
62
62
|
mapper.match(name, via: type) if actions.include? name
|
63
63
|
end
|
64
64
|
mapper.get 'list', action: :index if mapper.send(:parent_resource).actions.include? :index
|
@@ -72,47 +72,8 @@ end
|
|
72
72
|
|
73
73
|
module ActionDispatch
|
74
74
|
module Routing
|
75
|
-
ACTIVE_SCAFFOLD_CORE_ROUTING = ActiveScaffold::Routing::ACTIVE_SCAFFOLD_CORE_ROUTING
|
76
|
-
ACTIVE_SCAFFOLD_ASSOCIATION_ROUTING = ActiveScaffold::Routing::ACTIVE_SCAFFOLD_ASSOCIATION_ROUTING
|
77
|
-
|
78
75
|
class Mapper
|
79
76
|
module Resources
|
80
|
-
def parent_options
|
81
|
-
opts = parent_resource.instance_variable_get(:@options)
|
82
|
-
if Rails.version >= '5.0.0'
|
83
|
-
opts.merge(
|
84
|
-
only: parent_resource.instance_variable_get(:@only),
|
85
|
-
except: parent_resource.instance_variable_get(:@except)
|
86
|
-
)
|
87
|
-
end
|
88
|
-
opts
|
89
|
-
end
|
90
|
-
|
91
|
-
def define_active_scaffold_concern
|
92
|
-
ActiveSupport::Deprecation.warn 'Add concern :active_scaffold, ActiveScaffold::Routing::Basic.new(association: true) to your routes file.'
|
93
|
-
concern :active_scaffold, ActiveScaffold::Routing::Basic.new(association: true)
|
94
|
-
end
|
95
|
-
|
96
|
-
def define_active_scaffold_association_concern
|
97
|
-
ActiveSupport::Deprecation.warn 'Add concern :active_scaffold_association, ActiveScaffold::Routing::Association.new to your routes file.'
|
98
|
-
concern :active_scaffold_association, ActiveScaffold::Routing::Association.new
|
99
|
-
end
|
100
|
-
|
101
|
-
def as_routes(opts = {association: true})
|
102
|
-
define_active_scaffold_concern unless @concerns[:active_scaffold]
|
103
|
-
if opts[:association] && !@concerns[:active_scaffold_association]
|
104
|
-
define_active_scaffold_association_concern
|
105
|
-
end
|
106
|
-
ActiveSupport::Deprecation.warn 'Use concerns: :active_scaffold in resources instead of as_routes, or concerns :active_scaffold in resources block if want to disable association routes or restrict routes with only or except options.'
|
107
|
-
concerns :active_scaffold, parent_options.merge(association: opts[:association])
|
108
|
-
end
|
109
|
-
|
110
|
-
def as_association_routes
|
111
|
-
define_active_scaffold_association_concern unless @concerns[:active_scaffold_association]
|
112
|
-
ActiveSupport::Deprecation.warn 'Use concerns: :active_scaffold_association in resources instead of as_association_routes, or concerns :active_scaffold_association in resources block if want to restrict routes with only or except options.'
|
113
|
-
concerns :active_scaffold_association, parent_options
|
114
|
-
end
|
115
|
-
|
116
77
|
def as_nested_resources(*resources)
|
117
78
|
options = resources.extract_options!
|
118
79
|
nested_options = options.merge(parent_scaffold: parent_scaffold)
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# the ever-useful to_label method
|
2
2
|
class ActiveRecord::Base
|
3
3
|
def to_label
|
4
|
-
|
5
|
-
|
4
|
+
to_label_method = ActiveScaffold::Registry.cache :to_label, self.class.name do
|
5
|
+
%i[name label title to_s].find { |attribute| respond_to?(attribute) }
|
6
6
|
end
|
7
|
+
send(to_label_method).to_s if to_label_method
|
7
8
|
end
|
8
9
|
end
|
@@ -18,10 +18,8 @@ module ActiveScaffold::UnsavedRecord
|
|
18
18
|
def keeping_errors
|
19
19
|
old_errors = errors.dup if errors.present?
|
20
20
|
result = yield
|
21
|
-
|
22
|
-
old_errors.each
|
23
|
-
old_errors[attr].each { |msg| errors.add(attr, msg) unless errors.added?(attr, msg) }
|
24
|
-
end
|
21
|
+
old_errors&.each do |attr|
|
22
|
+
old_errors[attr].each { |msg| errors.add(attr, msg) unless errors.added?(attr, msg) }
|
25
23
|
end
|
26
24
|
result && old_errors.blank?
|
27
25
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveScaffold
|
2
2
|
module Finder
|
3
3
|
def self.like_operator
|
4
|
-
@@like_operator ||= ::ActiveRecord::Base.connection.adapter_name
|
4
|
+
@@like_operator ||= ::ActiveRecord::Base.connection.adapter_name.in?(%w[PostgreSQL PostGIS]) ? 'ILIKE' : 'LIKE'
|
5
5
|
end
|
6
6
|
|
7
7
|
module ClassMethods
|
@@ -68,7 +68,9 @@ module ActiveScaffold
|
|
68
68
|
value = columns_token[column.name]
|
69
69
|
value = /#{value}/ if column.text?
|
70
70
|
column.search_sql.map do |search_sql|
|
71
|
-
|
71
|
+
# call .to_s so String is returned from CowProxy::String in threadsafe mode
|
72
|
+
# in other case, or method from Mongoid would fail
|
73
|
+
{search_sql.to_s => value}
|
72
74
|
end
|
73
75
|
end.flatten
|
74
76
|
active_scaffold_config.model.or(token_conditions).selector
|
@@ -95,18 +97,16 @@ module ActiveScaffold
|
|
95
97
|
if respond_to?("condition_for_#{column.name}_column")
|
96
98
|
return send("condition_for_#{column.name}_column", column, value, like_pattern)
|
97
99
|
end
|
98
|
-
return unless column
|
100
|
+
return unless column&.search_sql && value.present?
|
99
101
|
search_ui = column.search_ui || column.column_type
|
100
102
|
begin
|
101
103
|
sql, *values =
|
102
104
|
if search_ui && respond_to?("condition_for_#{search_ui}_type")
|
103
105
|
send("condition_for_#{search_ui}_type", column, value, like_pattern)
|
106
|
+
elsif column.search_sql.instance_of? Proc
|
107
|
+
column.search_sql.call(value)
|
104
108
|
else
|
105
|
-
|
106
|
-
column.search_sql.call(value)
|
107
|
-
else
|
108
|
-
condition_for_search_ui(column, value, like_pattern, search_ui)
|
109
|
-
end
|
109
|
+
condition_for_search_ui(column, value, like_pattern, search_ui)
|
110
110
|
end
|
111
111
|
return nil unless sql
|
112
112
|
|
@@ -122,7 +122,7 @@ module ActiveScaffold
|
|
122
122
|
def condition_for_search_ui(column, value, like_pattern, search_ui)
|
123
123
|
case search_ui
|
124
124
|
when :boolean, :checkbox
|
125
|
-
['
|
125
|
+
['%<search_sql>s = ?', column.column ? ActiveScaffold::Core.column_type_cast(value, column.column) : value]
|
126
126
|
when :integer, :decimal, :float
|
127
127
|
condition_for_numeric(column, value)
|
128
128
|
when :string, :range
|
@@ -131,57 +131,59 @@ module ActiveScaffold
|
|
131
131
|
condition_for_datetime(column, value)
|
132
132
|
when :select, :multi_select, :country, :usa_state, :chosen, :multi_chosen
|
133
133
|
values = Array(value).select(&:present?)
|
134
|
-
['
|
134
|
+
['%<search_sql>s in (?)', values] if values.present?
|
135
135
|
else
|
136
136
|
if column.text?
|
137
|
-
["
|
137
|
+
["%<search_sql>s #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
|
138
138
|
else
|
139
|
-
['
|
139
|
+
['%<search_sql>s = ?', ActiveScaffold::Core.column_type_cast(value, column.column)]
|
140
140
|
end
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
144
|
def condition_for_numeric(column, value)
|
145
145
|
if !value.is_a?(Hash)
|
146
|
-
['
|
146
|
+
['%<search_sql>s = ?', condition_value_for_numeric(column, value)]
|
147
147
|
elsif ActiveScaffold::Finder::NULL_COMPARATORS.include?(value[:opt])
|
148
148
|
condition_for_null_type(column, value[:opt])
|
149
149
|
elsif value[:from].blank? || !ActiveScaffold::Finder::NUMERIC_COMPARATORS.include?(value[:opt])
|
150
150
|
nil
|
151
151
|
elsif value[:opt] == 'BETWEEN'
|
152
|
-
['(
|
152
|
+
['(%<search_sql>s BETWEEN ? AND ?)', condition_value_for_numeric(column, value[:from]), condition_value_for_numeric(column, value[:to])]
|
153
153
|
else
|
154
|
-
["
|
154
|
+
["%<search_sql>s #{value[:opt]} ?", condition_value_for_numeric(column, value[:from])]
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
158
158
|
def condition_for_range(column, value, like_pattern = nil)
|
159
159
|
if !value.is_a?(Hash)
|
160
160
|
if column.text?
|
161
|
-
["
|
161
|
+
["%<search_sql>s #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
|
162
162
|
else
|
163
|
-
['
|
163
|
+
['%<search_sql>s = ?', ActiveScaffold::Core.column_type_cast(value, column.column)]
|
164
164
|
end
|
165
165
|
elsif ActiveScaffold::Finder::NULL_COMPARATORS.include?(value[:opt])
|
166
166
|
condition_for_null_type(column, value[:opt], like_pattern)
|
167
167
|
elsif value[:from].blank?
|
168
168
|
nil
|
169
169
|
elsif ActiveScaffold::Finder::STRING_COMPARATORS.values.include?(value[:opt])
|
170
|
-
["
|
170
|
+
["%<search_sql>s #{ActiveScaffold::Finder.like_operator} ?", value[:opt].sub('?', value[:from])]
|
171
171
|
elsif value[:opt] == 'BETWEEN'
|
172
|
-
['(
|
172
|
+
['(%<search_sql>s BETWEEN ? AND ?)', value[:from], value[:to]]
|
173
173
|
elsif ActiveScaffold::Finder::NUMERIC_COMPARATORS.include?(value[:opt])
|
174
|
-
["
|
174
|
+
["%<search_sql>s #{value[:opt]} ?", value[:from]]
|
175
175
|
end
|
176
176
|
end
|
177
177
|
|
178
178
|
def tables_for_translating_days_and_months(format)
|
179
|
+
# rubocop:disable Style/FormatStringToken
|
179
180
|
keys = {
|
180
181
|
'%A' => 'date.day_names',
|
181
182
|
'%a' => 'date.abbr_day_names',
|
182
183
|
'%B' => 'date.month_names',
|
183
184
|
'%b' => 'date.abbr_month_names'
|
184
185
|
}
|
186
|
+
# rubocop:enable Style/FormatStringToken
|
185
187
|
key_index = keys.keys.map { |key| [key, format.index(key)] }.to_h
|
186
188
|
keys.select! { |k, _| key_index[k] }
|
187
189
|
keys.sort_by { |k, _| key_index[k] }.map do |_, k|
|
@@ -226,37 +228,60 @@ module ActiveScaffold
|
|
226
228
|
[format, parts[:offset]]
|
227
229
|
end
|
228
230
|
|
231
|
+
def local_time_from_hash(value, conversion = :to_time)
|
232
|
+
time = Time.zone.local(*%i[year month day hour minute second].collect { |part| value[part].to_i })
|
233
|
+
time.send(conversion)
|
234
|
+
rescue StandardError => e
|
235
|
+
message = "Error creating time from #{value.inspect}:"
|
236
|
+
Rails.logger.warn "#{message}\n#{e.message}\n#{e.backtrace.join("\n")}"
|
237
|
+
nil
|
238
|
+
end
|
239
|
+
|
240
|
+
def parse_date_with_format(value, format_name)
|
241
|
+
format = I18n.t("date.formats.#{format_name || :default}")
|
242
|
+
format.gsub!(/%-d|%-m|%_m/) { |s| s.gsub(/[-_]/, '') } # strptime fails with %-d, %-m, %_m
|
243
|
+
en_value = I18n.locale == :en ? value : translate_days_and_months(value, format)
|
244
|
+
Date.strptime(en_value, format)
|
245
|
+
rescue StandardError => e
|
246
|
+
message = "Error parsing date from #{en_value}"
|
247
|
+
message << " (#{value})" if en_value != value
|
248
|
+
message << ", with format #{format}" if format
|
249
|
+
Rails.logger.warn "#{message}:\n#{e.message}\n#{e.backtrace.join("\n")}"
|
250
|
+
nil
|
251
|
+
end
|
252
|
+
|
253
|
+
def parse_time_with_format(value, format, offset)
|
254
|
+
format.gsub!(/%-d|%-m|%_m/) { |s| s.gsub(/[-_]/, '') } # strptime fails with %-d, %-m, %_m
|
255
|
+
en_value = I18n.locale == :en ? value : translate_days_and_months(value, format)
|
256
|
+
time = Time.strptime(en_value, format)
|
257
|
+
offset ? time : Time.zone.local_to_utc(time).in_time_zone
|
258
|
+
rescue StandardError => e
|
259
|
+
message = "Error parsing time from #{en_value}"
|
260
|
+
message << " (#{value})" if en_value != value
|
261
|
+
message << ", with format #{format}" if format
|
262
|
+
Rails.logger.warn "#{message}:\n#{e.message}\n#{e.backtrace.join("\n")}"
|
263
|
+
nil
|
264
|
+
end
|
265
|
+
|
229
266
|
def condition_value_for_datetime(column, value, conversion = :to_time)
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
value.send(conversion)
|
241
|
-
end
|
242
|
-
elsif conversion == :to_date
|
243
|
-
format = I18n.t("date.formats.#{column.options[:format] || :default}")
|
244
|
-
format.gsub!(/%-d|%-m|%_m/) { |s| s.gsub(/[-_]/, '') } # strptime fails with %-d, %-m, %_m
|
245
|
-
value = translate_days_and_months(value, format) if I18n.locale != :en
|
246
|
-
Date.strptime(value, format) rescue nil
|
247
|
-
elsif value.include?('T')
|
248
|
-
Time.zone.parse(value)
|
249
|
-
else # datetime
|
250
|
-
format, offset = format_for_datetime(column, value)
|
251
|
-
format.gsub!(/%-d|%-m|%_m/) { |s| s.gsub(/[-_]/, '') } # strptime fails with %-d, %-m, %_m
|
252
|
-
value = translate_days_and_months(value, format) if I18n.locale != :en
|
253
|
-
time = DateTime.strptime(value, format) rescue nil
|
254
|
-
if time
|
255
|
-
time = Time.zone.local_to_utc(time).in_time_zone unless offset
|
256
|
-
time = time.send(conversion) unless conversion == :to_time
|
257
|
-
end
|
258
|
-
time
|
267
|
+
return if value.nil? || value.blank?
|
268
|
+
if value.is_a? Hash
|
269
|
+
local_time_from_hash(value, conversion)
|
270
|
+
elsif value.respond_to?(:strftime)
|
271
|
+
if conversion == :to_time
|
272
|
+
# Explicitly get the current zone, because TimeWithZone#to_time in rails 3.2.3 returns UTC.
|
273
|
+
# https://github.com/rails/rails/pull/2453
|
274
|
+
value.to_time.in_time_zone
|
275
|
+
else
|
276
|
+
value.send(conversion)
|
259
277
|
end
|
278
|
+
elsif conversion == :to_date
|
279
|
+
parse_date_with_format(value, column.options[:format])
|
280
|
+
elsif value.include?('T')
|
281
|
+
Time.zone.parse(value)
|
282
|
+
else # datetime
|
283
|
+
time = parse_time_with_format(value, *format_for_datetime(column, value))
|
284
|
+
conversion == :to_time ? time : time.send(conversion)
|
260
285
|
end
|
261
286
|
end
|
262
287
|
|
@@ -264,14 +289,15 @@ module ActiveScaffold
|
|
264
289
|
return value if value.nil?
|
265
290
|
value = column.number_to_native(value) if column.options[:format] && column.search_ui != :number
|
266
291
|
case (column.search_ui || column.column.type)
|
267
|
-
when :integer then
|
268
|
-
|
269
|
-
|
270
|
-
if Rails.version >= '4.2.0'
|
271
|
-
::ActiveRecord::Type::Decimal.new.type_cast_from_user(value)
|
292
|
+
when :integer then
|
293
|
+
if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
294
|
+
value ? 1 : 0
|
272
295
|
else
|
273
|
-
|
296
|
+
value.to_i
|
274
297
|
end
|
298
|
+
when :float then value.to_f
|
299
|
+
when :decimal
|
300
|
+
::ActiveRecord::Type::Decimal.new.type_cast_from_user(value)
|
275
301
|
else
|
276
302
|
value
|
277
303
|
end
|
@@ -293,28 +319,28 @@ module ActiveScaffold
|
|
293
319
|
if from_value.nil? && to_value.nil?
|
294
320
|
nil
|
295
321
|
elsif !from_value
|
296
|
-
['
|
322
|
+
['%<search_sql>s <= ?', to_value.to_s(:db)]
|
297
323
|
elsif !to_value
|
298
|
-
['
|
324
|
+
['%<search_sql>s >= ?', from_value.to_s(:db)]
|
299
325
|
else
|
300
|
-
['
|
326
|
+
['%<search_sql>s BETWEEN ? AND ?', from_value.to_s(:db), to_value.to_s(:db)]
|
301
327
|
end
|
302
328
|
end
|
303
329
|
|
304
330
|
def condition_for_record_select_type(column, value, like_pattern = nil)
|
305
331
|
if value.is_a?(Array)
|
306
|
-
['
|
332
|
+
['%<search_sql>s IN (?)', value]
|
307
333
|
else
|
308
|
-
['
|
334
|
+
['%<search_sql>s = ?', value]
|
309
335
|
end
|
310
336
|
end
|
311
337
|
|
312
338
|
def condition_for_null_type(column, value, like_pattern = nil)
|
313
339
|
case value.to_s
|
314
340
|
when 'null'
|
315
|
-
['
|
341
|
+
['%<search_sql>s is null', []]
|
316
342
|
when 'not_null'
|
317
|
-
['
|
343
|
+
['%<search_sql>s is not null', []]
|
318
344
|
end
|
319
345
|
end
|
320
346
|
end
|
@@ -366,10 +392,12 @@ module ActiveScaffold
|
|
366
392
|
@active_scaffold_references ||= []
|
367
393
|
end
|
368
394
|
|
369
|
-
# Override this method on your controller to define conditions to be used when querying a recordset (e.g. for List).
|
395
|
+
# Override this method on your controller to define conditions to be used when querying a recordset (e.g. for List).
|
396
|
+
# The return of this method should be any format compatible with the :conditions clause of ActiveRecord::Base's find.
|
370
397
|
def conditions_for_collection; end
|
371
398
|
|
372
|
-
# Override this method on your controller to define joins to be used when querying a recordset (e.g. for List).
|
399
|
+
# Override this method on your controller to define joins to be used when querying a recordset (e.g. for List).
|
400
|
+
# The return of this method should be any format compatible with the :joins clause of ActiveRecord::Base's find.
|
373
401
|
def joins_for_collection; end
|
374
402
|
|
375
403
|
# Override this method on your controller to provide custom finder options to the find() call. The return of this method should be a hash.
|
@@ -407,7 +435,10 @@ module ActiveScaffold
|
|
407
435
|
end
|
408
436
|
|
409
437
|
# valid options may include:
|
410
|
-
# * :sorting - a Sorting DataStructure (basically an array of hashes of field => direction,
|
438
|
+
# * :sorting - a Sorting DataStructure (basically an array of hashes of field => direction,
|
439
|
+
# e.g. [{:field1 => 'asc'}, {:field2 => 'desc'}]).
|
440
|
+
# please note that multi-column sorting has some limitations: if any column in a multi-field
|
441
|
+
# sort uses method-based sorting, it will be ignored. method sorting only works for single-column sorting.
|
411
442
|
# * :per_page
|
412
443
|
# * :page
|
413
444
|
def finder_options(options = {})
|
@@ -415,7 +446,7 @@ module ActiveScaffold
|
|
415
446
|
|
416
447
|
# create a general-use options array that's compatible with Rails finders
|
417
448
|
finder_options = {
|
418
|
-
:reorder => options[:sorting]
|
449
|
+
:reorder => options[:sorting]&.clause((grouped_columns_calculations if grouped_search?)).map(&Arel.method(:sql)),
|
419
450
|
:conditions => search_conditions
|
420
451
|
}
|
421
452
|
if active_scaffold_config.mongoid?
|
@@ -466,7 +497,7 @@ module ActiveScaffold
|
|
466
497
|
|
467
498
|
query = append_to_query(query, find_options)
|
468
499
|
# we build the paginator differently for method- and sql-based sorting
|
469
|
-
pager = if options[:sorting]
|
500
|
+
pager = if options[:sorting]&.sorts_by_method?
|
470
501
|
::Paginator.new(count, options[:per_page]) do |offset, per_page|
|
471
502
|
calculate_last_modified(query)
|
472
503
|
sorted_collection = sort_collection_by_column(query.to_a, *options[:sorting].first)
|
@@ -484,7 +515,7 @@ module ActiveScaffold
|
|
484
515
|
end
|
485
516
|
|
486
517
|
def calculate_last_modified(query)
|
487
|
-
return unless conditional_get_support? && query.klass
|
518
|
+
return unless conditional_get_support? && ActiveScaffold::OrmChecks.columns_hash(query.klass)['updated_at']
|
488
519
|
@last_modified = query.maximum(:updated_at)
|
489
520
|
end
|
490
521
|
|
@@ -501,13 +532,13 @@ module ActiveScaffold
|
|
501
532
|
end
|
502
533
|
|
503
534
|
def append_to_query(relation, options)
|
504
|
-
options.assert_valid_keys :where, :select, :having, :group, :reorder, :order, :limit, :offset,
|
535
|
+
options.assert_valid_keys :where, :select, :having, :group, :reorder, :order, :limit, :offset,
|
536
|
+
:joins, :left_joins, :left_outer_joins, :includes, :lock, :readonly,
|
537
|
+
:from, :conditions, :preload, :references
|
505
538
|
relation = options.reject { |_, v| v.blank? }.inject(relation) do |rel, (k, v)|
|
506
539
|
k == :conditions ? apply_conditions(rel, *v) : rel.send(k, v)
|
507
540
|
end
|
508
|
-
if options[:left_outer_joins].present? || options[:left_joins].present?
|
509
|
-
relation.distinct_value = true
|
510
|
-
end
|
541
|
+
relation.distinct_value = true if options[:left_outer_joins].present? || options[:left_joins].present?
|
511
542
|
relation
|
512
543
|
end
|
513
544
|
|
@@ -536,7 +567,7 @@ module ActiveScaffold
|
|
536
567
|
def sort_collection_by_column(collection, column, order)
|
537
568
|
sorter = column.sort[:method]
|
538
569
|
collection = collection.sort_by do |record|
|
539
|
-
value =
|
570
|
+
value = sorter.is_a?(Proc) ? record.instance_eval(&sorter) : record.instance_eval(sorter.to_s)
|
540
571
|
value = '' if value.nil?
|
541
572
|
value
|
542
573
|
end
|