active_scaffold 3.4.17 → 3.4.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +12 -1
- data/README.md +8 -4
- data/app/assets/javascripts/jquery/active_scaffold.js +82 -67
- data/app/assets/stylesheets/active_scaffold.scss +1 -1
- data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
- data/app/assets/stylesheets/blue-theme.css +1 -1
- data/app/views/active_scaffold_overrides/_form_association.html.erb +3 -3
- data/app/views/active_scaffold_overrides/_form_association_record.html.erb +3 -3
- data/app/views/active_scaffold_overrides/_show_columns.html.erb +1 -1
- data/lib/active_scaffold.rb +16 -16
- data/lib/active_scaffold/actions/common_search.rb +13 -11
- data/lib/active_scaffold/actions/core.rb +85 -78
- data/lib/active_scaffold/actions/create.rb +29 -28
- data/lib/active_scaffold/actions/delete.rb +17 -17
- data/lib/active_scaffold/actions/field_search.rb +18 -19
- data/lib/active_scaffold/actions/list.rb +30 -22
- data/lib/active_scaffold/actions/mark.rb +1 -1
- data/lib/active_scaffold/actions/nested.rb +78 -65
- data/lib/active_scaffold/actions/search.rb +13 -10
- data/lib/active_scaffold/actions/show.rb +10 -6
- data/lib/active_scaffold/actions/subform.rb +1 -2
- data/lib/active_scaffold/actions/update.rb +39 -31
- data/lib/active_scaffold/active_record_permissions.rb +14 -15
- data/lib/active_scaffold/attribute_params.rb +42 -43
- data/lib/active_scaffold/bridges.rb +22 -12
- data/lib/active_scaffold/bridges/ancestry.rb +1 -1
- data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +6 -6
- data/lib/active_scaffold/bridges/bitfields.rb +1 -1
- data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -13
- data/lib/active_scaffold/bridges/calendar_date_select.rb +5 -5
- data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +17 -20
- data/lib/active_scaffold/bridges/cancan.rb +1 -1
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +8 -9
- data/lib/active_scaffold/bridges/carrierwave.rb +4 -4
- data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +9 -8
- data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +11 -10
- data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +7 -6
- data/lib/active_scaffold/bridges/chosen.rb +1 -1
- data/lib/active_scaffold/bridges/chosen/helpers.rb +4 -4
- data/lib/active_scaffold/bridges/country_helper.rb +1 -1
- data/lib/active_scaffold/bridges/country_helper/country_helper_bridge.rb +259 -260
- data/lib/active_scaffold/bridges/date_picker.rb +2 -2
- data/lib/active_scaffold/bridges/date_picker/ext.rb +9 -11
- data/lib/active_scaffold/bridges/date_picker/helper.rb +61 -67
- data/lib/active_scaffold/bridges/dragonfly.rb +4 -4
- data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +9 -8
- data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +11 -10
- data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +6 -5
- data/lib/active_scaffold/bridges/file_column.rb +5 -5
- data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +20 -23
- data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +20 -23
- data/lib/active_scaffold/bridges/file_column/form_ui.rb +13 -14
- data/lib/active_scaffold/bridges/file_column/list_ui.rb +7 -8
- data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +18 -22
- data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +5 -4
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +2 -10
- data/lib/active_scaffold/bridges/paper_trail.rb +7 -5
- data/lib/active_scaffold/bridges/paper_trail/paper_trail_bridge.rb +4 -3
- data/lib/active_scaffold/bridges/paperclip.rb +5 -5
- data/lib/active_scaffold/bridges/paperclip/form_ui.rb +11 -10
- data/lib/active_scaffold/bridges/paperclip/list_ui.rb +6 -5
- data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +10 -9
- data/lib/active_scaffold/bridges/record_select.rb +1 -1
- data/lib/active_scaffold/bridges/record_select/helpers.rb +28 -28
- data/lib/active_scaffold/bridges/semantic_attributes.rb +1 -1
- data/lib/active_scaffold/bridges/semantic_attributes/column.rb +1 -1
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +58 -52
- data/lib/active_scaffold/bridges/tiny_mce.rb +2 -2
- data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -3
- data/lib/active_scaffold/config/base.rb +9 -10
- data/lib/active_scaffold/config/core.rb +24 -29
- data/lib/active_scaffold/config/create.rb +0 -1
- data/lib/active_scaffold/config/field_search.rb +8 -10
- data/lib/active_scaffold/config/form.rb +5 -5
- data/lib/active_scaffold/config/list.rb +21 -20
- data/lib/active_scaffold/config/mark.rb +3 -3
- data/lib/active_scaffold/config/nested.rb +11 -10
- data/lib/active_scaffold/config/search.rb +2 -3
- data/lib/active_scaffold/config/show.rb +1 -1
- data/lib/active_scaffold/config/update.rb +1 -2
- data/lib/active_scaffold/configurable.rb +9 -11
- data/lib/active_scaffold/constraints.rb +9 -8
- data/lib/active_scaffold/core.rb +72 -84
- data/lib/active_scaffold/data_structures/action_columns.rb +26 -25
- data/lib/active_scaffold/data_structures/action_link.rb +43 -43
- data/lib/active_scaffold/data_structures/action_links.rb +17 -15
- data/lib/active_scaffold/data_structures/actions.rb +5 -5
- data/lib/active_scaffold/data_structures/bridge.rb +6 -3
- data/lib/active_scaffold/data_structures/column.rb +110 -89
- data/lib/active_scaffold/data_structures/columns.rb +3 -3
- data/lib/active_scaffold/data_structures/error_message.rb +4 -6
- data/lib/active_scaffold/data_structures/nested_info.rb +43 -48
- data/lib/active_scaffold/data_structures/set.rb +7 -8
- data/lib/active_scaffold/data_structures/sorting.rb +38 -33
- data/lib/active_scaffold/delayed_setup.rb +5 -6
- data/lib/active_scaffold/engine.rb +4 -4
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +3 -4
- data/lib/active_scaffold/extensions/action_controller_rescueing.rb +1 -1
- data/lib/active_scaffold/extensions/action_view_rendering.rb +5 -6
- data/lib/active_scaffold/extensions/left_outer_joins.rb +11 -11
- data/lib/active_scaffold/extensions/localize.rb +1 -1
- data/lib/active_scaffold/extensions/name_option_for_datetime.rb +1 -1
- data/lib/active_scaffold/extensions/paginator_extensions.rb +2 -5
- data/lib/active_scaffold/extensions/reverse_associations.rb +13 -13
- data/lib/active_scaffold/extensions/routing_mapper.rb +9 -9
- data/lib/active_scaffold/extensions/unsaved_associated.rb +9 -9
- data/lib/active_scaffold/finder.rb +90 -93
- data/lib/active_scaffold/helpers/association_helpers.rb +5 -5
- data/lib/active_scaffold/helpers/controller_helpers.rb +22 -19
- data/lib/active_scaffold/helpers/form_column_helpers.rb +115 -105
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +62 -35
- data/lib/active_scaffold/helpers/id_helpers.rb +6 -6
- data/lib/active_scaffold/helpers/list_column_helpers.rb +89 -94
- data/lib/active_scaffold/helpers/pagination_helpers.rb +9 -9
- data/lib/active_scaffold/helpers/search_column_helpers.rb +47 -44
- data/lib/active_scaffold/helpers/show_column_helpers.rb +2 -2
- data/lib/active_scaffold/helpers/view_helpers.rb +86 -91
- data/lib/active_scaffold/marked_model.rb +10 -10
- data/lib/active_scaffold/paginator.rb +30 -34
- data/lib/active_scaffold/responds_to_parent.rb +27 -28
- data/lib/active_scaffold/tableless.rb +20 -15
- data/lib/active_scaffold/version.rb +1 -1
- data/lib/generators/active_scaffold/active_scaffold_generator.rb +8 -8
- data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +9 -9
- data/shoulda_macros/macros.rb +27 -22
- data/test/bridges/bridge_test.rb +38 -29
- data/test/bridges/date_picker_test.rb +1 -1
- data/test/bridges/paper_trail_test.rb +17 -0
- data/test/bridges/paperclip_test.rb +3 -2
- data/test/bridges/tiny_mce_test.rb +5 -2
- data/test/company.rb +25 -30
- data/test/config/base_test.rb +1 -1
- data/test/config/core_test.rb +9 -9
- data/test/config/create_test.rb +14 -8
- data/test/config/delete_test.rb +4 -4
- data/test/config/field_search_test.rb +6 -6
- data/test/config/list_test.rb +16 -16
- data/test/config/nested_test.rb +4 -4
- data/test/config/search_test.rb +8 -8
- data/test/config/show_test.rb +6 -6
- data/test/config/subform_test.rb +1 -1
- data/test/config/update_test.rb +5 -5
- data/test/const_mocker.rb +4 -4
- data/test/data_structures/action_columns_test.rb +4 -5
- data/test/data_structures/action_link_test.rb +1 -0
- data/test/data_structures/action_links_test.rb +5 -5
- data/test/data_structures/column_test.rb +9 -9
- data/test/data_structures/columns_test.rb +2 -2
- data/test/data_structures/error_message_test.rb +4 -5
- data/test/data_structures/set_test.rb +1 -2
- data/test/data_structures/sorting_test.rb +10 -10
- data/test/data_structures/validation_reflection_test.rb +8 -0
- data/test/extensions/routing_mapper_test.rb +2 -2
- data/test/helpers/list_column_helpers_test.rb +3 -2
- data/test/helpers/pagination_helpers_test.rb +5 -4
- data/test/helpers/search_column_helpers_test.rb +1 -1
- data/test/misc/active_record_permissions_test.rb +63 -50
- data/test/misc/attribute_params_test.rb +28 -26
- data/test/misc/calculation_test.rb +10 -3
- data/test/misc/configurable_test.rb +12 -13
- data/test/misc/constraints_test.rb +6 -6
- data/test/misc/convert_numbers_format_test.rb +7 -6
- data/test/misc/finder_test.rb +17 -12
- data/test/misc/lang_test.rb +3 -4
- data/test/misc/tableless_test.rb +2 -3
- data/test/mock_app/app/controllers/addresses_controller.rb +1 -1
- data/test/mock_app/app/controllers/buildings_controller.rb +1 -1
- data/test/mock_app/app/controllers/cars_controller.rb +1 -1
- data/test/mock_app/app/controllers/contacts_controller.rb +1 -1
- data/test/mock_app/app/controllers/people_controller.rb +1 -1
- data/test/mock_app/app/models/file_model.rb +2 -2
- data/test/mock_app/app/models/person.rb +1 -1
- data/test/mock_app/config/application.rb +3 -3
- data/test/mock_app/config/boot.rb +1 -1
- data/test/mock_app/config/environment.rb +1 -0
- data/test/mock_app/config/environments/development.rb +0 -1
- data/test/mock_app/config/environments/production.rb +1 -1
- data/test/mock_app/db/schema.rb +14 -15
- data/test/model_stub.rb +13 -16
- data/test/run_all.rb +5 -7
- data/test/test_helper.rb +12 -9
- metadata +19 -3
@@ -16,7 +16,7 @@ module ActiveScaffold
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def reverse(klass = nil)
|
19
|
-
unless defined? @reverse
|
19
|
+
unless defined? @reverse # rubocop:disable Style/IfUnlessModifier
|
20
20
|
@reverse ||= inverse_of.try(:name)
|
21
21
|
end
|
22
22
|
@reverse || (autodetect_inverse(klass).try(:name) unless klass.nil?)
|
@@ -27,10 +27,10 @@ module ActiveScaffold
|
|
27
27
|
klass ||= self.klass
|
28
28
|
|
29
29
|
# name-based matching (association name vs self.active_record.to_s)
|
30
|
-
matches =
|
30
|
+
matches = reverse_matches(klass)
|
31
31
|
if matches.length > 1
|
32
32
|
matches.find_all do |assoc|
|
33
|
-
|
33
|
+
active_record.to_s.underscore.include? assoc.name.to_s.pluralize.singularize
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -42,8 +42,9 @@ module ActiveScaffold
|
|
42
42
|
def self.included(base)
|
43
43
|
base.send :include, ActiveScaffold::ReverseAssociation::CommonMethods
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
protected
|
47
|
+
|
47
48
|
def reverse_matches(klass)
|
48
49
|
reverse_matches = []
|
49
50
|
|
@@ -52,20 +53,20 @@ module ActiveScaffold
|
|
52
53
|
next if assoc == self
|
53
54
|
# skip over has_many :through associations
|
54
55
|
next if assoc.options[:through]
|
55
|
-
next unless assoc.options[:polymorphic]
|
56
|
+
next unless assoc.options[:polymorphic] || assoc.class_name == active_record.name
|
56
57
|
|
57
|
-
case [assoc.macro,
|
58
|
+
case [assoc.macro, macro].find_all { |m| m == :has_and_belongs_to_many }.length
|
58
59
|
# if both are a habtm, then match them based on the join table
|
59
60
|
when 2
|
60
|
-
|
61
|
+
next unless assoc.options[:join_table] == options[:join_table]
|
61
62
|
|
62
63
|
# if only one is a habtm, they do not match
|
63
64
|
when 1
|
64
|
-
|
65
|
+
next
|
65
66
|
|
66
67
|
# otherwise, match them based on the foreign_key
|
67
68
|
when 0
|
68
|
-
|
69
|
+
next unless assoc.foreign_key.to_sym == foreign_key.to_sym
|
69
70
|
end
|
70
71
|
|
71
72
|
reverse_matches << assoc
|
@@ -89,15 +90,14 @@ module ActiveScaffold
|
|
89
90
|
next if assoc == self
|
90
91
|
# only iterate has_many :through associations
|
91
92
|
next unless assoc.options[:through]
|
92
|
-
next unless assoc.class_name ==
|
93
|
-
next unless assoc.through_reflection.class_name ==
|
94
|
-
|
93
|
+
next unless assoc.class_name == active_record.name
|
94
|
+
next unless assoc.through_reflection.class_name == through_reflection.class_name
|
95
|
+
|
95
96
|
reverse_matches << assoc
|
96
97
|
end
|
97
98
|
reverse_matches
|
98
99
|
end
|
99
100
|
end
|
100
|
-
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module ActionDispatch
|
2
2
|
module Routing
|
3
3
|
ACTIVE_SCAFFOLD_CORE_ROUTING = {
|
4
|
-
|
5
|
-
|
4
|
+
:collection => {:show_search => :get, :render_field => :post, :mark => :post},
|
5
|
+
:member => {:update_column => :post, :render_field => [:get, :post], :mark => :post}
|
6
6
|
}
|
7
7
|
ACTIVE_SCAFFOLD_ASSOCIATION_ROUTING = {
|
8
|
-
|
9
|
-
|
8
|
+
:collection => {:edit_associated => :get, :new_existing => :get, :add_existing => :post},
|
9
|
+
:member => {:edit_associated => :get, :destroy_existing => :delete}
|
10
10
|
}
|
11
|
-
|
11
|
+
|
12
12
|
class Mapper
|
13
13
|
module Resources
|
14
14
|
class ActiveScaffold < Resource
|
@@ -39,10 +39,10 @@ module ActionDispatch
|
|
39
39
|
end
|
40
40
|
as_association_routes if opts[:association]
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def as_association_routes
|
44
44
|
resource_scope(:resource, ActiveScaffoldAssociation.new(parent_resource.name, parent_resource.options)) do
|
45
|
-
collection do
|
45
|
+
collection do
|
46
46
|
ActionDispatch::Routing::ACTIVE_SCAFFOLD_ASSOCIATION_ROUTING[:collection].each do |name, type|
|
47
47
|
match(name, :via => type) if parent_resource.actions.include? name
|
48
48
|
end
|
@@ -54,14 +54,14 @@ module ActionDispatch
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
def as_nested_resources(*resources)
|
59
59
|
options = resources.extract_options!
|
60
60
|
resources.each do |resource|
|
61
61
|
resources(resource, options.merge(:parent_scaffold => merge_module_scope(@scope[:module], parent_resource.plural), :association => resource)) { yield if block_given? }
|
62
62
|
end
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
def as_scoped_routes(*scopes)
|
66
66
|
options = scopes.extract_options!
|
67
67
|
scopes.each do |scope|
|
@@ -9,15 +9,15 @@ class ActiveRecord::Base
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def save_associated
|
12
|
-
with_unsaved_associated { |a| a.save
|
12
|
+
with_unsaved_associated { |a| a.save && a.save_associated }
|
13
13
|
end
|
14
14
|
|
15
15
|
def save_associated!
|
16
|
-
save_associated
|
16
|
+
save_associated || raise(ActiveRecord::RecordNotSaved)
|
17
17
|
end
|
18
18
|
|
19
19
|
def no_errors_in_associated?
|
20
|
-
with_unsaved_associated {|a| a.errors.count == 0
|
20
|
+
with_unsaved_associated { |a| a.errors.count == 0 && a.no_errors_in_associated? }
|
21
21
|
end
|
22
22
|
|
23
23
|
protected
|
@@ -33,10 +33,10 @@ class ActiveRecord::Base
|
|
33
33
|
#
|
34
34
|
# Otherwise the default behaviour of traversing all associations will be preserved.
|
35
35
|
def associations_for_update
|
36
|
-
if self.respond_to?(
|
37
|
-
self.class.reflect_on_all_associations.reject { |association|
|
38
|
-
elsif self.respond_to?(
|
39
|
-
self.class.reflect_on_all_associations.select { |association|
|
36
|
+
if self.respond_to?(:scaffold_update_nofollow)
|
37
|
+
self.class.reflect_on_all_associations.reject { |association| scaffold_update_nofollow.include?(association.name) }
|
38
|
+
elsif self.respond_to?(:scaffold_update_follow)
|
39
|
+
self.class.reflect_on_all_associations.select { |association| scaffold_update_follow.include?(association.name) }
|
40
40
|
else
|
41
41
|
self.class.reflect_on_all_associations
|
42
42
|
end
|
@@ -49,11 +49,11 @@ class ActiveRecord::Base
|
|
49
49
|
# returns true otherwise, even when none of the associations have been instantiated. build wrapper methods accordingly.
|
50
50
|
def with_unsaved_associated
|
51
51
|
associations_for_update.all? do |assoc|
|
52
|
-
association_proxy =
|
52
|
+
association_proxy = association(assoc.name)
|
53
53
|
if association_proxy.target.present?
|
54
54
|
records = association_proxy.target
|
55
55
|
records = [records] unless records.is_a? Array # convert singular associations into collections for ease of use
|
56
|
-
records.select {|r| r.unsaved?
|
56
|
+
records.select { |r| r.unsaved? && !r.readonly? }.all? { |r| yield r } # must use select instead of find_all, which Rails overrides on association proxies for db access
|
57
57
|
else
|
58
58
|
true
|
59
59
|
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 == 'PostgreSQL' ? 'ILIKE' : 'LIKE'
|
5
5
|
end
|
6
6
|
|
7
7
|
module ClassMethods
|
@@ -24,11 +24,10 @@ module ActiveScaffold
|
|
24
24
|
phrase = where_clauses.join(' OR ')
|
25
25
|
|
26
26
|
tokens.collect do |value|
|
27
|
-
columns.
|
27
|
+
columns.each_with_object([phrase]) do |column, condition|
|
28
28
|
Array(column.search_sql).size.times do
|
29
29
|
condition.push(column.text? ? like_pattern.sub('?', value) : ActiveScaffold::Core.column_type_cast(value, column.column))
|
30
30
|
end
|
31
|
-
condition
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
@@ -39,57 +38,62 @@ module ActiveScaffold
|
|
39
38
|
def condition_for_column(column, value, text_search = :full)
|
40
39
|
like_pattern = like_pattern(text_search)
|
41
40
|
if self.respond_to?("condition_for_#{column.name}_column")
|
42
|
-
return
|
41
|
+
return send("condition_for_#{column.name}_column", column, value, like_pattern)
|
43
42
|
end
|
44
|
-
return unless column
|
43
|
+
return unless column && column.search_sql && !value.blank?
|
45
44
|
search_ui = column.search_ui || column.column.try(:type)
|
46
45
|
begin
|
47
|
-
sql, *values =
|
48
|
-
self.
|
49
|
-
|
50
|
-
if column.search_sql.instance_of? Proc
|
51
|
-
column.search_sql.call(value)
|
46
|
+
sql, *values =
|
47
|
+
if search_ui && self.respond_to?("condition_for_#{search_ui}_type")
|
48
|
+
send("condition_for_#{search_ui}_type", column, value, like_pattern)
|
52
49
|
else
|
53
|
-
|
54
|
-
|
55
|
-
["%{search_sql} = ?", column.column ? ActiveScaffold::Core.column_type_cast(value, column.column) : value]
|
56
|
-
when :integer, :decimal, :float
|
57
|
-
condition_for_numeric(column, value)
|
58
|
-
when :string, :range
|
59
|
-
condition_for_range(column, value, like_pattern)
|
60
|
-
when :date, :time, :datetime, :timestamp
|
61
|
-
condition_for_datetime(column, value)
|
62
|
-
when :select, :multi_select, :country, :usa_state, :chosen, :multi_chosen
|
63
|
-
["%{search_sql} in (?)", Array(value)]
|
50
|
+
if column.search_sql.instance_of? Proc
|
51
|
+
column.search_sql.call(value)
|
64
52
|
else
|
65
|
-
|
66
|
-
["%{search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
|
67
|
-
else
|
68
|
-
["%{search_sql} = ?", ActiveScaffold::Core.column_type_cast(value, column.column)]
|
69
|
-
end
|
53
|
+
condition_for_search_ui(column, value, like_pattern, search_ui)
|
70
54
|
end
|
71
55
|
end
|
72
|
-
end
|
73
56
|
return nil unless sql
|
74
57
|
|
75
58
|
conditions = [column.search_sql.collect { |search_sql| sql % {:search_sql => search_sql} }.join(' OR ')]
|
76
|
-
conditions += values*column.search_sql.size if values.present?
|
59
|
+
conditions += values * column.search_sql.size if values.present?
|
77
60
|
conditions
|
78
|
-
rescue
|
79
|
-
logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column :#{column.name}, search_ui = #{search_ui} in #{
|
61
|
+
rescue StandardError => e
|
62
|
+
logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column :#{column.name}, search_ui = #{search_ui} in #{name}"
|
80
63
|
raise e
|
81
64
|
end
|
82
65
|
end
|
83
66
|
|
67
|
+
def condition_for_search_ui(column, value, like_pattern, search_ui)
|
68
|
+
case search_ui
|
69
|
+
when :boolean, :checkbox
|
70
|
+
['%{search_sql} = ?', column.column ? ActiveScaffold::Core.column_type_cast(value, column.column) : value]
|
71
|
+
when :integer, :decimal, :float
|
72
|
+
condition_for_numeric(column, value)
|
73
|
+
when :string, :range
|
74
|
+
condition_for_range(column, value, like_pattern)
|
75
|
+
when :date, :time, :datetime, :timestamp
|
76
|
+
condition_for_datetime(column, value)
|
77
|
+
when :select, :multi_select, :country, :usa_state, :chosen, :multi_chosen
|
78
|
+
['%{search_sql} in (?)', Array(value)]
|
79
|
+
else
|
80
|
+
if column.text?
|
81
|
+
["%{search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
|
82
|
+
else
|
83
|
+
['%{search_sql} = ?', ActiveScaffold::Core.column_type_cast(value, column.column)]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
84
88
|
def condition_for_numeric(column, value)
|
85
89
|
if !value.is_a?(Hash)
|
86
|
-
[
|
87
|
-
elsif ActiveScaffold::Finder::
|
90
|
+
['%{search_sql} = ?', condition_value_for_numeric(column, value)]
|
91
|
+
elsif ActiveScaffold::Finder::NULL_COMPARATORS.include?(value[:opt])
|
88
92
|
condition_for_null_type(column, value[:opt])
|
89
|
-
elsif value[:from].blank?
|
93
|
+
elsif value[:from].blank? || !ActiveScaffold::Finder::NUMERIC_COMPARATORS.include?(value[:opt])
|
90
94
|
nil
|
91
95
|
elsif value[:opt] == 'BETWEEN'
|
92
|
-
[
|
96
|
+
['(%{search_sql} BETWEEN ? AND ?)', condition_value_for_numeric(column, value[:from]), condition_value_for_numeric(column, value[:to])]
|
93
97
|
else
|
94
98
|
["%{search_sql} #{value[:opt]} ?", condition_value_for_numeric(column, value[:from])]
|
95
99
|
end
|
@@ -100,20 +104,18 @@ module ActiveScaffold
|
|
100
104
|
if column.text?
|
101
105
|
["%{search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
|
102
106
|
else
|
103
|
-
[
|
107
|
+
['%{search_sql} = ?', ActiveScaffold::Core.column_type_cast(value, column.column)]
|
104
108
|
end
|
105
|
-
elsif ActiveScaffold::Finder::
|
109
|
+
elsif ActiveScaffold::Finder::NULL_COMPARATORS.include?(value[:opt])
|
106
110
|
condition_for_null_type(column, value[:opt], like_pattern)
|
107
111
|
elsif value[:from].blank?
|
108
112
|
nil
|
109
|
-
elsif ActiveScaffold::Finder::
|
113
|
+
elsif ActiveScaffold::Finder::STRING_COMPARATORS.values.include?(value[:opt])
|
110
114
|
["%{search_sql} #{ActiveScaffold::Finder.like_operator} ?", value[:opt].sub('?', value[:from])]
|
111
115
|
elsif value[:opt] == 'BETWEEN'
|
112
|
-
[
|
113
|
-
elsif ActiveScaffold::Finder::
|
116
|
+
['(%{search_sql} BETWEEN ? AND ?)', value[:from], value[:to]]
|
117
|
+
elsif ActiveScaffold::Finder::NUMERIC_COMPARATORS.include?(value[:opt])
|
114
118
|
["%{search_sql} #{value[:opt]} ?", value[:from]]
|
115
|
-
else
|
116
|
-
nil
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
@@ -135,7 +137,7 @@ module ActiveScaffold
|
|
135
137
|
|
136
138
|
def condition_value_for_datetime(column, value, conversion = :to_time)
|
137
139
|
if value.is_a? Hash
|
138
|
-
Time.zone.local(*[:year, :month, :day, :hour, :minute, :second].collect {|part| value[part].to_i}) rescue nil
|
140
|
+
Time.zone.local(*[:year, :month, :day, :hour, :minute, :second].collect { |part| value[part].to_i }) rescue nil
|
139
141
|
elsif value.respond_to?(:strftime)
|
140
142
|
if conversion == :to_time
|
141
143
|
# Explicitly get the current zone, because TimeWithZone#to_time in rails 3.2.3 returns UTC.
|
@@ -150,11 +152,11 @@ module ActiveScaffold
|
|
150
152
|
parts = Date._parse(value)
|
151
153
|
format = I18n.translate "time.formats.#{column.options[:format] || :picker}", :default => '' if ActiveScaffold.js_framework == :jquery
|
152
154
|
if format.blank?
|
153
|
-
time_parts = [[:hour, '%H'], [:min, '%M'], [:sec, '%S']].collect {|part, format_part| format_part if parts[part].present?}.compact
|
155
|
+
time_parts = [[:hour, '%H'], [:min, '%M'], [:sec, '%S']].collect { |part, format_part| format_part if parts[part].present? }.compact
|
154
156
|
format = "#{I18n.t('date.formats.default')} #{time_parts.join(':')} #{'%z' if parts[:offset].present?}"
|
155
157
|
else
|
156
158
|
if parts[:hour]
|
157
|
-
[[:min, '%M'], [:sec, '%S']].each {|part, f| format.gsub!(":#{f}", '') unless parts[part].present?}
|
159
|
+
[[:min, '%M'], [:sec, '%S']].each { |part, f| format.gsub!(":#{f}", '') unless parts[part].present? }
|
158
160
|
else
|
159
161
|
value += ' 00:00:00'
|
160
162
|
end
|
@@ -198,33 +200,31 @@ module ActiveScaffold
|
|
198
200
|
from_value = condition_value_for_datetime(column, value[:from], conversion)
|
199
201
|
to_value = condition_value_for_datetime(column, value[:to], conversion)
|
200
202
|
|
201
|
-
if from_value.nil?
|
203
|
+
if from_value.nil? && to_value.nil?
|
202
204
|
nil
|
203
205
|
elsif !from_value
|
204
|
-
[
|
206
|
+
['%{search_sql} <= ?', to_value.to_s(:db)]
|
205
207
|
elsif !to_value
|
206
|
-
[
|
208
|
+
['%{search_sql} >= ?', from_value.to_s(:db)]
|
207
209
|
else
|
208
|
-
[
|
210
|
+
['%{search_sql} BETWEEN ? AND ?', from_value.to_s(:db), to_value.to_s(:db)]
|
209
211
|
end
|
210
212
|
end
|
211
213
|
|
212
214
|
def condition_for_record_select_type(column, value, like_pattern = nil)
|
213
215
|
if value.is_a?(Array)
|
214
|
-
[
|
216
|
+
['%{search_sql} IN (?)', value]
|
215
217
|
else
|
216
|
-
[
|
218
|
+
['%{search_sql} = ?', value]
|
217
219
|
end
|
218
220
|
end
|
219
221
|
|
220
222
|
def condition_for_null_type(column, value, like_pattern = nil)
|
221
|
-
case value.
|
222
|
-
when
|
223
|
-
[
|
224
|
-
when
|
225
|
-
[
|
226
|
-
else
|
227
|
-
nil
|
223
|
+
case value.to_s
|
224
|
+
when 'null'
|
225
|
+
['%{search_sql} is null', []]
|
226
|
+
when 'not_null'
|
227
|
+
['%{search_sql} is not null', []]
|
228
228
|
end
|
229
229
|
end
|
230
230
|
|
@@ -238,7 +238,7 @@ module ActiveScaffold
|
|
238
238
|
end
|
239
239
|
end
|
240
240
|
|
241
|
-
|
241
|
+
NUMERIC_COMPARATORS = [
|
242
242
|
'=',
|
243
243
|
'>=',
|
244
244
|
'<=',
|
@@ -247,17 +247,12 @@ module ActiveScaffold
|
|
247
247
|
'!=',
|
248
248
|
'BETWEEN'
|
249
249
|
]
|
250
|
-
|
250
|
+
STRING_COMPARATORS = {
|
251
251
|
:contains => '%?%',
|
252
252
|
:begins_with => '?%',
|
253
253
|
:ends_with => '%?'
|
254
254
|
}
|
255
|
-
|
256
|
-
'null',
|
257
|
-
'not_null'
|
258
|
-
]
|
259
|
-
|
260
|
-
|
255
|
+
NULL_COMPARATORS = %w(null not_null)
|
261
256
|
|
262
257
|
def self.included(klass)
|
263
258
|
klass.extend ClassMethods
|
@@ -282,7 +277,7 @@ module ActiveScaffold
|
|
282
277
|
|
283
278
|
def active_scaffold_includes
|
284
279
|
ActiveSupport::Deprecation.warn "active_scaffold_includes doesn't exist anymore, use active_scaffold_preload, active_scaffold_outer_joins or active_scaffold_references"
|
285
|
-
|
280
|
+
active_scaffold_preload
|
286
281
|
end
|
287
282
|
|
288
283
|
attr_writer :active_scaffold_habtm_joins
|
@@ -335,7 +330,7 @@ module ActiveScaffold
|
|
335
330
|
record = klass.find(id)
|
336
331
|
security_options = {:crud_type => security_options.to_sym} unless security_options.is_a? Hash
|
337
332
|
raise ActiveScaffold::RecordNotAllowed, "#{klass} with id = #{id}" unless record.authorized_for? security_options
|
338
|
-
|
333
|
+
record
|
339
334
|
end
|
340
335
|
# valid options may include:
|
341
336
|
# * :sorting - a Sorting DataStructure (basically an array of hashes of field => direction, e.g. [{:field1 => 'asc'}, {:field2 => 'desc'}]). please note that multi-column sorting has some limitations: if any column in a multi-field sort uses method-based sorting, it will be ignored. method sorting only works for single-column sorting.
|
@@ -346,13 +341,15 @@ module ActiveScaffold
|
|
346
341
|
full_includes = (active_scaffold_references.blank? ? nil : active_scaffold_references)
|
347
342
|
|
348
343
|
# create a general-use options array that's compatible with Rails finders
|
349
|
-
finder_options = {
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
344
|
+
finder_options = {
|
345
|
+
:reorder => options[:sorting].try(:clause),
|
346
|
+
:conditions => search_conditions,
|
347
|
+
:joins => joins_for_finder,
|
348
|
+
:outer_joins => active_scaffold_outer_joins,
|
349
|
+
:preload => active_scaffold_preload,
|
350
|
+
:includes => full_includes,
|
351
|
+
:select => options[:select]
|
352
|
+
}
|
356
353
|
if Rails::VERSION::MAJOR >= 4
|
357
354
|
if options[:sorting].try(:sorts_by_sql?)
|
358
355
|
options[:sorting].each do |col, _|
|
@@ -368,7 +365,7 @@ module ActiveScaffold
|
|
368
365
|
|
369
366
|
def count_items(query, find_options = {}, count_includes = nil)
|
370
367
|
count_includes ||= find_options[:includes] unless find_options[:conditions].blank?
|
371
|
-
options = find_options.reject{|k,
|
368
|
+
options = find_options.reject { |k, _| [:select, :reorder].include? k }
|
372
369
|
# NOTE: we must use includes in the count query, because some conditions may reference other tables
|
373
370
|
options[:includes] = count_includes
|
374
371
|
|
@@ -384,7 +381,7 @@ module ActiveScaffold
|
|
384
381
|
# See finder_options for valid options
|
385
382
|
def find_page(options = {})
|
386
383
|
options.assert_valid_keys :sorting, :per_page, :page, :count_includes, :pagination, :select
|
387
|
-
options[:per_page] ||=
|
384
|
+
options[:per_page] ||= 999_999_999
|
388
385
|
options[:page] ||= 1
|
389
386
|
|
390
387
|
find_options = finder_options(options)
|
@@ -397,7 +394,7 @@ module ActiveScaffold
|
|
397
394
|
|
398
395
|
query = append_to_query(query, find_options)
|
399
396
|
# we build the paginator differently for method- and sql-based sorting
|
400
|
-
if options[:sorting]
|
397
|
+
if options[:sorting] && options[:sorting].sorts_by_method?
|
401
398
|
pager = ::Paginator.new(count, options[:per_page]) do |offset, per_page|
|
402
399
|
calculate_last_modified(query)
|
403
400
|
sorted_collection = sort_collection_by_column(query.to_a, *options[:sorting].first)
|
@@ -415,9 +412,8 @@ module ActiveScaffold
|
|
415
412
|
end
|
416
413
|
|
417
414
|
def calculate_last_modified(query)
|
418
|
-
|
419
|
-
|
420
|
-
end
|
415
|
+
return unless conditional_get_support? && query.klass.columns_hash['updated_at']
|
416
|
+
@last_modified = query.maximum(:updated_at)
|
421
417
|
end
|
422
418
|
|
423
419
|
def calculate_query
|
@@ -428,28 +424,29 @@ module ActiveScaffold
|
|
428
424
|
outer_joins += includes if includes
|
429
425
|
primary_key = active_scaffold_config.model.primary_key
|
430
426
|
subquery = append_to_query(beginning_of_chain, :conditions => conditions, :joins => joins_for_finder, :outer_joins => outer_joins, :select => active_scaffold_config.columns[primary_key].field)
|
427
|
+
subquery = subquery.unscope(:order) if Rails::VERSION::MAJOR >= 4
|
431
428
|
active_scaffold_config.model.where(primary_key => subquery)
|
432
429
|
end
|
433
430
|
|
434
|
-
def append_to_query(
|
431
|
+
def append_to_query(relation, options)
|
435
432
|
options.assert_valid_keys :where, :select, :group, :reorder, :limit, :offset, :joins, :outer_joins, :includes, :lock, :readonly, :from, :conditions, :preload, (:references if Rails::VERSION::MAJOR >= 4)
|
436
|
-
|
437
|
-
k == :conditions ? apply_conditions(
|
433
|
+
relation = options.reject { |_, v| v.blank? }.inject(relation) do |rel, (k, v)|
|
434
|
+
k == :conditions ? apply_conditions(rel, *v) : rel.send(k, v)
|
438
435
|
end
|
439
436
|
if options[:outer_joins].present?
|
440
437
|
if Rails::VERSION::MAJOR >= 4
|
441
|
-
|
438
|
+
relation.distinct_value = true
|
442
439
|
else
|
443
|
-
|
440
|
+
relation = relation.uniq
|
444
441
|
end
|
445
442
|
end
|
446
|
-
|
443
|
+
relation
|
447
444
|
end
|
448
445
|
|
449
446
|
def joins_for_finder
|
450
447
|
case joins_for_collection
|
451
448
|
when String
|
452
|
-
[
|
449
|
+
[joins_for_collection]
|
453
450
|
when Array
|
454
451
|
joins_for_collection
|
455
452
|
else
|
@@ -457,12 +454,12 @@ module ActiveScaffold
|
|
457
454
|
end + active_scaffold_habtm_joins
|
458
455
|
end
|
459
456
|
|
460
|
-
def apply_conditions(
|
461
|
-
conditions.reject(&:blank?).inject(
|
457
|
+
def apply_conditions(relation, *conditions)
|
458
|
+
conditions.reject(&:blank?).inject(relation) do |rel, condition|
|
462
459
|
if condition.is_a?(Array) && !condition.first.is_a?(String) # multiple conditions
|
463
|
-
apply_conditions(
|
460
|
+
apply_conditions(rel, *condition)
|
464
461
|
else
|
465
|
-
|
462
|
+
rel.where(condition)
|
466
463
|
end
|
467
464
|
end
|
468
465
|
end
|
@@ -470,11 +467,11 @@ module ActiveScaffold
|
|
470
467
|
# TODO: this should reside on the column, not the controller
|
471
468
|
def sort_collection_by_column(collection, column, order)
|
472
469
|
sorter = column.sort[:method]
|
473
|
-
collection = collection.sort_by
|
470
|
+
collection = collection.sort_by do |record|
|
474
471
|
value = (sorter.is_a? Proc) ? record.instance_eval(&sorter) : record.instance_eval(sorter.to_s)
|
475
472
|
value = '' if value.nil?
|
476
473
|
value
|
477
|
-
|
474
|
+
end
|
478
475
|
collection.reverse! if order.downcase == 'desc'
|
479
476
|
collection
|
480
477
|
end
|