active_scaffold 3.5.3 → 3.6.0.rc2
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} +73 -0
- data/README.md +17 -7
- data/app/assets/javascripts/active_scaffold.js.erb +0 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +97 -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.html.erb +2 -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 +9 -7
- data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +4 -4
- data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +2 -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/_vertical_subform.html.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 +2 -2
- 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 +91 -70
- 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 +23 -22
- 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 +102 -94
- 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 +34 -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/paper_trail/actions.rb +3 -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 +15 -17
- 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 +67 -28
- 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 +38 -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 +33 -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 +95 -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 +110 -77
- 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 +34 -10
- data/lib/active_scaffold/helpers/form_column_helpers.rb +196 -124
- 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 +86 -57
- 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 +55 -20
- data/app/assets/javascripts/prototype/rico_corner.js +0 -370
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -7
@@ -24,11 +24,11 @@ module ActiveScaffold::Actions
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def destroy_respond_to_xml
|
27
|
-
render :xml => successful? ? '' : response_object, :only => active_scaffold_config.list.columns.
|
27
|
+
render :xml => successful? ? '' : response_object, :only => active_scaffold_config.list.columns.visible_columns_names, :status => response_status
|
28
28
|
end
|
29
29
|
|
30
30
|
def destroy_respond_to_json
|
31
|
-
render :json => successful? ? '' : response_object, :only => active_scaffold_config.list.columns.
|
31
|
+
render :json => successful? ? '' : response_object, :only => active_scaffold_config.list.columns.visible_columns_names, :status => response_status
|
32
32
|
end
|
33
33
|
|
34
34
|
def destroy_find_record
|
@@ -65,7 +65,7 @@ module ActiveScaffold::Actions
|
|
65
65
|
private
|
66
66
|
|
67
67
|
def delete_authorized_filter
|
68
|
-
link = active_scaffold_config.delete.link || active_scaffold_config.delete.class.link
|
68
|
+
link = active_scaffold_config.delete.link || self.class.active_scaffold_config.delete.class.link
|
69
69
|
raise ActiveScaffold::ActionNotAllowed unless Array(send(link.security_method))[0]
|
70
70
|
end
|
71
71
|
|
@@ -23,11 +23,11 @@ module ActiveScaffold::Actions
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def store_search_params_into_session
|
26
|
-
|
26
|
+
init_field_search_params(active_scaffold_config.field_search.default_params) unless active_scaffold_config.field_search.default_params.nil?
|
27
27
|
super
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
30
|
+
def init_field_search_params(default_params)
|
31
31
|
return unless (params[:search].is_a?(String) || search_params.nil?) && params[:search].blank?
|
32
32
|
params[:search] = default_params.is_a?(Proc) ? instance_eval(&default_params) : default_params
|
33
33
|
end
|
@@ -56,24 +56,25 @@ module ActiveScaffold::Actions
|
|
56
56
|
|
57
57
|
def custom_finder_options
|
58
58
|
if grouped_search?
|
59
|
-
group_sql = calculation_for_group_by(search_group_column
|
60
|
-
|
61
|
-
|
62
|
-
select_query = quoted_select_columns(search_group_column.try(:select_columns))
|
59
|
+
group_sql = calculation_for_group_by(search_group_column&.field || search_group_name)
|
60
|
+
select_query = grouped_search_select
|
63
61
|
select_query << group_sql.as(search_group_column.name.to_s) if search_group_column && group_sql.respond_to?(:to_sql)
|
64
|
-
|
65
|
-
select_query << active_scaffold_config.columns[active_scaffold_config.model.inheritance_column].field
|
66
|
-
end
|
67
|
-
grouped_columns_calculations.each do |name, part|
|
68
|
-
select_query << (part.respond_to?(:as) ? part : Arel::Nodes::SqlLiteral.new(part)).as(name.to_s)
|
69
|
-
end
|
70
|
-
|
71
|
-
{group: group_by, select: select_query}
|
62
|
+
{group: group_sql, select: select_query}
|
72
63
|
else
|
73
64
|
super
|
74
65
|
end
|
75
66
|
end
|
76
67
|
|
68
|
+
def grouped_search_select
|
69
|
+
select_query = quoted_select_columns(search_group_column&.select_columns || [search_group_name])
|
70
|
+
if active_scaffold_config.model.columns_hash.include?(active_scaffold_config.model.inheritance_column)
|
71
|
+
select_query << active_scaffold_config.columns[active_scaffold_config.model.inheritance_column].field
|
72
|
+
end
|
73
|
+
grouped_columns_calculations.each do |name, part|
|
74
|
+
select_query << (part.respond_to?(:as) ? part : Arel::Nodes::SqlLiteral.new(part)).as(name.to_s)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
77
78
|
def grouped_columns_calculations
|
78
79
|
@grouped_columns_calculations ||= list_columns[1..-1].each_with_object({}) do |c, h|
|
79
80
|
h[c.name] = calculation_for_group_search(c)
|
@@ -113,12 +114,13 @@ module ActiveScaffold::Actions
|
|
113
114
|
end
|
114
115
|
|
115
116
|
def list_columns
|
116
|
-
@list_columns ||=
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
@list_columns ||=
|
118
|
+
if grouped_search?
|
119
|
+
columns = grouped_columns || super.select(&:calculation?)
|
120
|
+
columns.unshift(search_group_column || search_group_name)
|
121
|
+
else
|
122
|
+
super
|
123
|
+
end
|
122
124
|
end
|
123
125
|
|
124
126
|
def grouped_columns
|
@@ -142,34 +144,42 @@ module ActiveScaffold::Actions
|
|
142
144
|
|
143
145
|
def do_search
|
144
146
|
if field_search_params.present?
|
145
|
-
|
146
|
-
text_search = active_scaffold_config.field_search.text_search
|
147
|
-
columns = active_scaffold_config.field_search.columns
|
148
|
-
count_includes = active_scaffold_config.list.user.count_includes
|
149
|
-
search_params.each do |key, value|
|
150
|
-
next unless columns.include? key
|
151
|
-
column = active_scaffold_config.columns[key]
|
152
|
-
search_condition = self.class.condition_for_column(column, value, text_search)
|
153
|
-
next if search_condition.blank?
|
154
|
-
|
155
|
-
if count_includes.nil? && column.includes.present? && list_columns.include?(column) && !grouped_search?
|
156
|
-
active_scaffold_references << column.includes
|
157
|
-
elsif column.search_joins.present?
|
158
|
-
active_scaffold_outer_joins << column.search_joins
|
159
|
-
end
|
160
|
-
active_scaffold_conditions << search_condition
|
161
|
-
filtered_columns << column
|
162
|
-
end
|
163
|
-
if filtered_columns.present? || grouped_search?
|
164
|
-
@filtered = active_scaffold_config.field_search.human_conditions ? filtered_columns : true
|
165
|
-
end
|
166
|
-
|
167
|
-
active_scaffold_config.list.user.page = nil
|
147
|
+
do_field_search
|
168
148
|
else
|
169
149
|
super
|
170
150
|
end
|
171
151
|
end
|
172
152
|
|
153
|
+
def do_field_search
|
154
|
+
filtered_columns = []
|
155
|
+
text_search = active_scaffold_config.field_search.text_search
|
156
|
+
columns = active_scaffold_config.field_search.columns
|
157
|
+
count_includes = active_scaffold_config.list.user.count_includes
|
158
|
+
search_params.each do |key, value|
|
159
|
+
next unless columns.include? key
|
160
|
+
column = active_scaffold_config.columns[key]
|
161
|
+
search_condition = self.class.condition_for_column(column, value, text_search)
|
162
|
+
next if search_condition.blank?
|
163
|
+
|
164
|
+
joins_for_search_on_column(column, count_includes)
|
165
|
+
active_scaffold_conditions << search_condition
|
166
|
+
filtered_columns << column
|
167
|
+
end
|
168
|
+
if filtered_columns.present? || grouped_search?
|
169
|
+
@filtered = active_scaffold_config.field_search.human_conditions ? filtered_columns : true
|
170
|
+
end
|
171
|
+
|
172
|
+
active_scaffold_config.list.user.page = nil
|
173
|
+
end
|
174
|
+
|
175
|
+
def joins_for_search_on_column(column, count_includes)
|
176
|
+
if count_includes.nil? && column.includes.present? && list_columns.include?(column) && !grouped_search?
|
177
|
+
active_scaffold_references << column.includes
|
178
|
+
elsif column.search_joins.present?
|
179
|
+
active_scaffold_outer_joins << column.search_joins
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
173
183
|
def field_search_ignore?
|
174
184
|
active_scaffold_config.list.always_show_search && active_scaffold_config.list.search_partial == 'field_search'
|
175
185
|
end
|
@@ -2,7 +2,7 @@ module ActiveScaffold::Actions
|
|
2
2
|
module List
|
3
3
|
def self.included(base)
|
4
4
|
base.before_action :list_authorized_filter, :only => :index
|
5
|
-
base.helper_method :list_columns
|
5
|
+
base.helper_method :list_columns, :count_on_association_class?
|
6
6
|
end
|
7
7
|
|
8
8
|
def index
|
@@ -49,11 +49,11 @@ module ActiveScaffold::Actions
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def list_respond_to_xml
|
52
|
-
|
52
|
+
response_to_api(:xml, list_columns_names)
|
53
53
|
end
|
54
54
|
|
55
55
|
def list_respond_to_json
|
56
|
-
|
56
|
+
response_to_api(:json, list_columns_names)
|
57
57
|
end
|
58
58
|
|
59
59
|
def row_respond_to_html
|
@@ -71,7 +71,7 @@ module ActiveScaffold::Actions
|
|
71
71
|
if respond_to?(:"#{action}_columns", true)
|
72
72
|
send(:"#{action}_columns")
|
73
73
|
else
|
74
|
-
active_scaffold_config.send(action).columns.
|
74
|
+
active_scaffold_config.send(action).columns.visible_columns(flatten: true)
|
75
75
|
end
|
76
76
|
joins_cols, preload_cols = columns.select { |c| c.includes.present? }.partition do |col|
|
77
77
|
includes_need_join?(col, sorting) && !grouped_search?
|
@@ -82,7 +82,7 @@ module ActiveScaffold::Actions
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def set_includes_for_sorting(columns, sorting)
|
85
|
-
sorting.
|
85
|
+
sorting.each_column do |col|
|
86
86
|
next unless col.includes.present? && !columns.include?(col)
|
87
87
|
if active_scaffold_config.model.connection.needs_order_expressions_in_select?
|
88
88
|
active_scaffold_references << col.includes
|
@@ -93,12 +93,12 @@ module ActiveScaffold::Actions
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def includes_need_join?(column, sorting = active_scaffold_config.list.user.sorting)
|
96
|
-
sorting.sorts_on?(column) || scoped_habtm?(column)
|
96
|
+
(sorting.sorts_by_sql? && sorting.sorts_on?(column)) || scoped_habtm?(column)
|
97
97
|
end
|
98
98
|
|
99
99
|
def scoped_habtm?(column)
|
100
|
-
assoc = column.association if column.association
|
101
|
-
assoc
|
100
|
+
assoc = column.association if column.association&.collection?
|
101
|
+
assoc&.habtm? && assoc.scope
|
102
102
|
end
|
103
103
|
|
104
104
|
def get_row(crud_type_or_security_options = :read)
|
@@ -106,37 +106,115 @@ module ActiveScaffold::Actions
|
|
106
106
|
super
|
107
107
|
end
|
108
108
|
|
109
|
+
def current_page
|
110
|
+
set_includes_for_columns
|
111
|
+
|
112
|
+
page = find_page(find_page_options)
|
113
|
+
total_pages = page.pager.number_of_pages
|
114
|
+
if !page.pager.infinite? && !total_pages.zero? && page.number > total_pages
|
115
|
+
page = page.pager.last
|
116
|
+
active_scaffold_config.list.user.page = page.number
|
117
|
+
end
|
118
|
+
page
|
119
|
+
end
|
120
|
+
|
109
121
|
# The actual algorithm to prepare for the list view
|
110
122
|
def do_list
|
111
123
|
# id: nil needed in params_for because rails reuse it even
|
112
124
|
# if it was deleted from params (like do_refresh_list does)
|
113
125
|
@remove_id_from_list_links = params[:id].blank?
|
114
|
-
|
126
|
+
@page = current_page
|
127
|
+
@records = @page.items
|
128
|
+
cache_column_counts
|
129
|
+
end
|
130
|
+
|
131
|
+
def columns_to_cache_counts
|
132
|
+
list_columns.select do |col|
|
133
|
+
col.association&.collection? && col.includes.blank? && col.associated_number? &&
|
134
|
+
!ActiveScaffold::OrmChecks.tableless?(col.association.klass) &&
|
135
|
+
!col.association.reverse_association&.counter_cache
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def cache_column_counts
|
140
|
+
@counts = columns_to_cache_counts.each_with_object({}) do |column, counts|
|
141
|
+
if ActiveScaffold::OrmChecks.active_record?(column.association.klass)
|
142
|
+
counts[column.name] = count_query_for_column(column).count
|
143
|
+
elsif ActiveScaffold::OrmChecks.mongoid?(column.association.klass)
|
144
|
+
counts[column.name] = mongoid_count_for_column(column)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def count_on_association_class?(column)
|
150
|
+
column.association.has_many? && !column.association.through? &&
|
151
|
+
(!column.association.as || column.association.reverse_association)
|
152
|
+
end
|
153
|
+
|
154
|
+
def count_query_for_column(column)
|
155
|
+
if count_on_association_class?(column)
|
156
|
+
count_query_on_association_class(column)
|
157
|
+
else
|
158
|
+
count_query_with_join(column)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def count_query_on_association_class(column)
|
163
|
+
key = column.association.primary_key || :id
|
164
|
+
query = column.association.klass.where(column.association.foreign_key => @records.map(&key))
|
165
|
+
if column.association.as
|
166
|
+
query.where!(column.association.reverse_association.foreign_type => active_scaffold_config.model.name)
|
167
|
+
end
|
168
|
+
if column.association.scope
|
169
|
+
query = query.instance_exec(&column.association.scope)
|
170
|
+
end
|
171
|
+
query.group(column.association.foreign_key)
|
172
|
+
end
|
173
|
+
|
174
|
+
def count_query_with_join(column)
|
175
|
+
klass = column.association.klass
|
176
|
+
query = active_scaffold_config.model.where(active_scaffold_config.primary_key => @records.map(&:id))
|
177
|
+
.joins(column.name).group(active_scaffold_config.primary_key)
|
178
|
+
.select("#{klass.quoted_table_name}.#{klass.quoted_primary_key}")
|
179
|
+
query = query.uniq if column.association.scope && klass.instance_exec(&column.association.scope).values[:distinct]
|
180
|
+
query
|
181
|
+
end
|
182
|
+
|
183
|
+
def mongoid_count_for_column(column)
|
184
|
+
matches = {column.association.foreign_key => {'$in': @records.map(&:id)}}
|
185
|
+
if column.association.as
|
186
|
+
matches[column.association.reverse_association.foreign_type] = {'$eq': active_scaffold_config.model.name}
|
187
|
+
end
|
188
|
+
group = {_id: "$#{column.association.foreign_key}", count: {'$sum' => 1}}
|
189
|
+
query = column.association.klass.collection.aggregate([{'$match' => matches}, {'$group' => group}])
|
190
|
+
query.each_with_object({}) do |row, hash|
|
191
|
+
hash[row['_id']] = row['count']
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def find_page_options
|
196
|
+
options = {
|
197
|
+
:sorting => active_scaffold_config.list.user.sorting,
|
198
|
+
:count_includes => active_scaffold_config.list.user.count_includes
|
199
|
+
}
|
115
200
|
|
116
|
-
|
117
|
-
:count_includes => active_scaffold_config.list.user.count_includes}
|
118
|
-
paginate = params[:format].nil? ? (accepts? :html, :js) : %w[html js].include?(params[:format])
|
201
|
+
paginate = params[:format].nil? ? accepts?(:html, :js) : %w[html js].include?(params[:format])
|
119
202
|
options[:pagination] = active_scaffold_config.list.pagination if paginate
|
120
203
|
if options[:pagination]
|
121
204
|
options[:per_page] = active_scaffold_config.list.user.per_page
|
122
205
|
options[:page] = active_scaffold_config.list.user.page
|
123
206
|
end
|
207
|
+
|
124
208
|
if active_scaffold_config.list.auto_select_columns
|
125
209
|
auto_select_columns = list_columns + [active_scaffold_config.columns[active_scaffold_config.model.primary_key]]
|
126
210
|
options[:select] = auto_select_columns.map { |c| quoted_select_columns(c.select_columns) }.compact.flatten
|
127
211
|
end
|
128
212
|
|
129
|
-
|
130
|
-
total_pages = page.pager.number_of_pages
|
131
|
-
if !page.pager.infinite? && !total_pages.zero? && page.number > total_pages
|
132
|
-
page = page.pager.last
|
133
|
-
active_scaffold_config.list.user.page = page.number
|
134
|
-
end
|
135
|
-
@page, @records = page, page.items
|
213
|
+
options
|
136
214
|
end
|
137
215
|
|
138
216
|
def quoted_select_columns(columns)
|
139
|
-
columns
|
217
|
+
columns&.map { |c| active_scaffold_config.columns[c]&.field || c }
|
140
218
|
end
|
141
219
|
|
142
220
|
def do_refresh_list
|
@@ -149,17 +227,23 @@ module ActiveScaffold::Actions
|
|
149
227
|
end
|
150
228
|
|
151
229
|
def each_record_in_page
|
152
|
-
|
153
|
-
do_search if respond_to? :do_search, true
|
154
|
-
active_scaffold_config.list.user.page = current_page
|
155
|
-
do_list
|
156
|
-
@page.items.each { |record| yield record }
|
230
|
+
page_items.each { |record| yield record }
|
157
231
|
end
|
158
232
|
|
159
233
|
def each_record_in_scope
|
160
234
|
scoped_query.each { |record| yield record }
|
161
235
|
end
|
162
236
|
|
237
|
+
def page_items
|
238
|
+
@page_items ||= begin
|
239
|
+
page_number = active_scaffold_config.list.user.page
|
240
|
+
do_search if respond_to? :do_search, true
|
241
|
+
active_scaffold_config.list.user.page = page_number
|
242
|
+
@page = current_page
|
243
|
+
@page.items
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
163
247
|
def scoped_query
|
164
248
|
@scoped_query ||= begin
|
165
249
|
do_search if respond_to? :do_search, true
|
@@ -189,7 +273,7 @@ module ActiveScaffold::Actions
|
|
189
273
|
{:etag => active_scaffold_config.list.user.sorting.clause}
|
190
274
|
end
|
191
275
|
end
|
192
|
-
objects.
|
276
|
+
objects.presence || super
|
193
277
|
end
|
194
278
|
|
195
279
|
private
|
@@ -216,7 +300,7 @@ module ActiveScaffold::Actions
|
|
216
300
|
end
|
217
301
|
|
218
302
|
def list_columns
|
219
|
-
@list_columns ||= active_scaffold_config.list.columns.
|
303
|
+
@list_columns ||= active_scaffold_config.list.columns.visible_columns
|
220
304
|
end
|
221
305
|
|
222
306
|
def list_columns_names
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module ActiveScaffold::Actions
|
2
|
-
# The Nested module basically handles automatically linking controllers together.
|
2
|
+
# The Nested module basically handles automatically linking controllers together.
|
3
|
+
# It does this by creating column links with the right parameters, and by providing
|
4
|
+
# any supporting systems (like a /:controller/nested action for returning associated scaffolds).
|
3
5
|
module Nested
|
4
6
|
def self.included(base)
|
5
7
|
super
|
@@ -27,17 +29,17 @@ module ActiveScaffold::Actions
|
|
27
29
|
def set_nested
|
28
30
|
@nested = nil
|
29
31
|
return unless params[:parent_scaffold] && (params[:association] || params[:named_scope])
|
30
|
-
@nested = ActiveScaffold::DataStructures::NestedInfo.get(active_scaffold_config.model, params)
|
31
|
-
register_constraints_with_action_columns(@nested.constrained_fields) unless @nested.nil?
|
32
|
+
@nested = ActiveScaffold::DataStructures::NestedInfo.get(self.class.active_scaffold_config.model, params)
|
32
33
|
end
|
33
34
|
|
34
35
|
def configure_nested
|
35
36
|
return unless nested?
|
37
|
+
register_constraints_with_action_columns(nested.constrained_fields)
|
38
|
+
return unless active_scaffold_config.actions.include? :list
|
36
39
|
active_scaffold_config.list.user.label = nested_label
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
40
|
+
return if active_scaffold_config.nested.ignore_order_from_association
|
41
|
+
chain = beginning_of_chain
|
42
|
+
active_scaffold_config.list.user.nested_default_sorting = nested_default_sorting(chain) if nested.sorted?(chain)
|
41
43
|
end
|
42
44
|
|
43
45
|
def nested_label
|
@@ -57,41 +59,39 @@ module ActiveScaffold::Actions
|
|
57
59
|
end
|
58
60
|
|
59
61
|
def include_habtm_actions
|
60
|
-
if nested
|
62
|
+
if nested&.habtm?
|
61
63
|
# Production mode is ok with adding a link everytime the scaffold is nested - we are not ok with that.
|
62
|
-
|
63
|
-
|
64
|
-
active_scaffold_config.action_links.add('destroy_existing', :label => :remove, :type => :member, :confirm => :are_you_sure_to_delete, :method => :delete, :position => false, :security_method => :delete_existing_authorized?) unless active_scaffold_config.action_links['destroy_existing']
|
65
|
-
if active_scaffold_config.actions.include?(:delete)
|
66
|
-
active_scaffold_config.action_links.delete('destroy') if active_scaffold_config.action_links['destroy']
|
67
|
-
end
|
68
|
-
end
|
69
|
-
else
|
70
|
-
# Production mode is caching this link into a non nested scaffold
|
71
|
-
active_scaffold_config.action_links.delete('new_existing') if active_scaffold_config.action_links['new_existing']
|
72
|
-
|
73
|
-
if active_scaffold_config.nested.shallow_delete
|
74
|
-
active_scaffold_config.action_links.delete('destroy_existing') if active_scaffold_config.action_links['destroy_existing']
|
75
|
-
if active_scaffold_config.actions.include?(:delete) && active_scaffold_config.delete.link
|
76
|
-
active_scaffold_config.action_links.add(active_scaffold_config.delete.link) unless active_scaffold_config.action_links['destroy']
|
77
|
-
end
|
64
|
+
unless active_scaffold_config.action_links['new_existing']
|
65
|
+
active_scaffold_config.action_links.add('new_existing', :label => :add_existing, :type => :collection, :security_method => :add_existing_authorized?)
|
78
66
|
end
|
67
|
+
add_shallow_links if active_scaffold_config.nested.shallow_delete
|
68
|
+
elsif !ActiveScaffold.threadsafe
|
69
|
+
# Production mode is caching this link into a non nested scaffold, when threadsafe is disabled
|
70
|
+
active_scaffold_config.action_links.delete('new_existing')
|
71
|
+
restore_shallow_links if active_scaffold_config.nested.shallow_delete
|
79
72
|
end
|
80
73
|
end
|
81
74
|
|
75
|
+
def add_shallow_links
|
76
|
+
unless active_scaffold_config.action_links['destroy_existing']
|
77
|
+
link_options = {:label => :remove, :type => :member, :confirm => :are_you_sure_to_delete, :method => :delete, :position => false, :security_method => :delete_existing_authorized?}
|
78
|
+
active_scaffold_config.action_links.add('destroy_existing', link_options)
|
79
|
+
end
|
80
|
+
active_scaffold_config.action_links.delete('destroy') if active_scaffold_config.actions.include?(:delete)
|
81
|
+
end
|
82
|
+
|
83
|
+
def restore_shallow_links
|
84
|
+
if active_scaffold_config.actions.include?(:delete) && active_scaffold_config.delete.link
|
85
|
+
link = active_scaffold_config.delete.link
|
86
|
+
active_scaffold_config.action_links.add(link) unless active_scaffold_config.action_links[link.action]
|
87
|
+
end
|
88
|
+
active_scaffold_config.action_links.delete('destroy_existing')
|
89
|
+
end
|
90
|
+
|
82
91
|
def beginning_of_chain
|
83
|
-
if nested
|
84
|
-
|
85
|
-
|
86
|
-
elsif nested.association.through? # has_one :through
|
87
|
-
active_scaffold_config.model.where(active_scaffold_config.model.primary_key => nested_parent_record.send(nested.association.name).try(:id))
|
88
|
-
elsif nested.association.has_one?
|
89
|
-
active_scaffold_config.model.where(nested.child_association.foreign_key => nested_parent_record.send(nested.association.association_primary_key))
|
90
|
-
elsif nested.association.belongs_to?
|
91
|
-
nested_belongs_to_chain
|
92
|
-
else # never should get here
|
93
|
-
active_scaffold_config.model
|
94
|
-
end
|
92
|
+
# only if nested is related to current controller, e.g. not when adding record in subform inside subform
|
93
|
+
if nested? && nested.match_model?(active_scaffold_config.model)
|
94
|
+
nested_chain_with_association
|
95
95
|
elsif nested? && nested.scope
|
96
96
|
nested_parent_record.send(nested.scope)
|
97
97
|
else
|
@@ -99,23 +99,40 @@ module ActiveScaffold::Actions
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
102
|
+
def nested_chain_with_association
|
103
|
+
if nested.association.collection?
|
104
|
+
nested_parent_record.send(nested.association.name)
|
105
|
+
elsif nested.association.through? # has_one :through
|
106
|
+
active_scaffold_config.model.where(active_scaffold_config.model.primary_key => nested_parent_record.send(nested.association.name)&.id)
|
107
|
+
elsif nested.association.has_one?
|
108
|
+
active_scaffold_config.model.where(nested.child_association.name => nested_parent_record)
|
109
|
+
elsif nested.association.belongs_to?
|
110
|
+
primary_key = active_scaffold_config.mongoid? ? '_id' : active_scaffold_config.model.primary_key
|
111
|
+
active_scaffold_config.model.where(primary_key => nested_parent_record.send(nested.association.name))
|
112
|
+
else # never should get here
|
113
|
+
raise 'missing condition for nested beginning_of_chain'
|
114
|
+
end
|
105
115
|
end
|
106
116
|
|
107
117
|
def nested_parent_record(crud = :read)
|
108
118
|
@nested_parent_record ||= find_if_allowed(nested.parent_id, crud, nested.parent_model)
|
109
119
|
end
|
110
120
|
|
121
|
+
def create_association_with_parent?
|
122
|
+
# has_many is done by beginning_of_chain and rails if direct association, not in through associations
|
123
|
+
return false if nested.has_many? && !nested.association.through?
|
124
|
+
nested.child_association && nested_parent_record
|
125
|
+
end
|
126
|
+
|
111
127
|
def create_association_with_parent(record)
|
112
|
-
|
113
|
-
return unless (nested.belongs_to? || nested.has_one? || nested.habtm?) && nested.child_association
|
114
|
-
return if (parent = nested_parent_record).nil?
|
128
|
+
return unless create_association_with_parent?
|
115
129
|
if nested.child_association.singular?
|
116
|
-
record.send("#{nested.child_association.name}=",
|
130
|
+
record.send("#{nested.child_association.name}=", nested_parent_record)
|
131
|
+
elsif nested.association.through_singular? && nested.child_association.through_singular?
|
132
|
+
through = nested_parent_record.send(nested.association.through_reflection.name)
|
133
|
+
record.send("#{nested.child_association.through_reflection.name}=", through)
|
117
134
|
else
|
118
|
-
record.send(nested.child_association.name) <<
|
135
|
+
record.send(nested.child_association.name) << nested_parent_record
|
119
136
|
end
|
120
137
|
end
|
121
138
|
|
@@ -181,11 +198,11 @@ module ActiveScaffold::Actions::Nested
|
|
181
198
|
end
|
182
199
|
|
183
200
|
def add_existing_respond_to_xml
|
184
|
-
render :xml => response_object, :only => active_scaffold_config.list.columns.
|
201
|
+
render :xml => response_object, :only => active_scaffold_config.list.columns.visible_columns_names, :status => response_status
|
185
202
|
end
|
186
203
|
|
187
204
|
def add_existing_respond_to_json
|
188
|
-
render :json => response_object, :only => active_scaffold_config.list.columns.
|
205
|
+
render :json => response_object, :only => active_scaffold_config.list.columns.visible_columns_names, :status => response_status
|
189
206
|
end
|
190
207
|
|
191
208
|
def destroy_existing_respond_to_html
|
@@ -198,11 +215,11 @@ module ActiveScaffold::Actions::Nested
|
|
198
215
|
end
|
199
216
|
|
200
217
|
def destroy_existing_respond_to_xml
|
201
|
-
render :xml => successful? ? '' : response_object, :only => active_scaffold_config.list.columns.
|
218
|
+
render :xml => successful? ? '' : response_object, :only => active_scaffold_config.list.columns.visible_columns_names, :status => response_status
|
202
219
|
end
|
203
220
|
|
204
221
|
def destroy_existing_respond_to_json
|
205
|
-
render :json => successful? ? '' : response_object, :only => active_scaffold_config.list.columns.
|
222
|
+
render :json => successful? ? '' : response_object, :only => active_scaffold_config.list.columns.visible_columns_names, :status => response_status
|
206
223
|
end
|
207
224
|
|
208
225
|
def add_existing_authorized?(record = nil)
|