active_scaffold 3.4.17 → 3.4.18
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 +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
|