active_scaffold 3.5.5 → 3.6.1
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} +75 -0
- data/README.md +21 -10
- data/app/assets/javascripts/active_scaffold.js.erb +0 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +98 -7
- 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 +26 -10
- 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 +2 -1
- data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
- data/lib/active_scaffold/bridges/bitfields/list_ui.rb +19 -0
- data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +3 -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 +7 -6
- 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 +93 -32
- 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 +18 -16
- 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 +90 -57
- data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
- data/lib/active_scaffold/helpers/search_column_helpers.rb +43 -41
- data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
- data/lib/active_scaffold/helpers/view_helpers.rb +39 -36
- 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 +83 -67
- 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 +52 -4
- 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/action_view_rendering_test.rb +20 -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 +3 -3
- 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 +14 -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 +5 -1
- data/test/mock_app/app/controllers/roles_controller.rb +4 -0
- data/test/mock_app/app/views/active_scaffold_overrides/_form.html.erb +2 -0
- data/test/mock_app/app/views/active_scaffold_overrides/list.html.erb +2 -0
- data/test/mock_app/app/views/people/_first_name_form_column.html.erb +2 -0
- data/test/mock_app/app/views/people/_form.html.erb +2 -0
- data/test/mock_app/app/views/people/list.html.erb +2 -0
- 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 +12 -4
- metadata +71 -15
- data/app/assets/javascripts/prototype/rico_corner.js +0 -370
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -7
@@ -1,29 +1,37 @@
|
|
1
1
|
module ActiveScaffold::DataStructures
|
2
2
|
class ActionLink
|
3
|
+
NO_OPTIONS = {}.freeze
|
4
|
+
|
3
5
|
# provides a quick way to set any property of the object from a hash
|
4
6
|
def initialize(action, options = {})
|
5
7
|
# set defaults
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
@action = action
|
9
|
+
@label = action
|
10
|
+
@confirm = false
|
11
|
+
@type = :collection
|
12
|
+
@method = :get
|
13
|
+
@crud_type =
|
14
|
+
case action&.to_sym
|
15
|
+
when :destroy then :delete
|
16
|
+
when :create, :new then :create
|
17
|
+
when :update, :edit then :update
|
18
|
+
else :read
|
19
|
+
end
|
20
|
+
@column = nil
|
21
|
+
@image = nil
|
22
|
+
@controller = nil
|
23
|
+
@parameters = nil
|
24
|
+
@dynamic_parameters = nil
|
25
|
+
@html_options = nil
|
26
|
+
@weight = 0
|
10
27
|
self.inline = true
|
11
|
-
self.method = :get
|
12
|
-
self.crud_type = :delete if [:destroy].include?(action.try(:to_sym))
|
13
|
-
self.crud_type = :create if %i[create new].include?(action.try(:to_sym))
|
14
|
-
self.crud_type = :update if %i[edit update].include?(action.try(:to_sym))
|
15
|
-
self.crud_type ||= :read
|
16
|
-
self.column = nil
|
17
|
-
self.image = nil
|
18
|
-
self.dynamic_parameters = nil
|
19
|
-
self.weight = 0
|
20
28
|
|
21
29
|
# apply quick properties
|
22
30
|
options.each_pair do |k, v|
|
23
31
|
setter = "#{k}="
|
24
32
|
send(setter, v) if respond_to? setter
|
25
33
|
end
|
26
|
-
self.toggle = self.action
|
34
|
+
self.toggle = self.action&.to_sym == :index && !position && (parameters.present? || dynamic_parameters) unless options.include? :toggle
|
27
35
|
end
|
28
36
|
|
29
37
|
def initialize_copy(action_link)
|
@@ -52,7 +60,8 @@ module ActiveScaffold::DataStructures
|
|
52
60
|
# a hash of request parameters
|
53
61
|
attr_writer :parameters
|
54
62
|
def parameters
|
55
|
-
@parameters
|
63
|
+
return @parameters || NO_OPTIONS if frozen?
|
64
|
+
@parameters ||= NO_OPTIONS.dup
|
56
65
|
end
|
57
66
|
|
58
67
|
# if active class is added to link when current request matches link
|
@@ -69,7 +78,7 @@ module ActiveScaffold::DataStructures
|
|
69
78
|
# what string to use to represent this action
|
70
79
|
attr_writer :label
|
71
80
|
def label
|
72
|
-
@label.is_a?(Symbol) ? as_(@label) : @label
|
81
|
+
@label.is_a?(Symbol) ? ActiveScaffold::Registry.cache(:translations, @label) { as_(@label) } : @label
|
73
82
|
end
|
74
83
|
|
75
84
|
# image to use {:name => 'arrow.png', :size => '16x16'}
|
@@ -82,7 +91,8 @@ module ActiveScaffold::DataStructures
|
|
82
91
|
end
|
83
92
|
|
84
93
|
def confirm(label = '')
|
85
|
-
@confirm
|
94
|
+
return @confirm if !confirm? || @confirm.is_a?(String)
|
95
|
+
ActiveScaffold::Registry.cache(:translations, @confirm) { as_(@confirm) } % {label: label}
|
86
96
|
end
|
87
97
|
|
88
98
|
def confirm?
|
@@ -186,7 +196,8 @@ module ActiveScaffold::DataStructures
|
|
186
196
|
# html options for the link
|
187
197
|
attr_writer :html_options
|
188
198
|
def html_options
|
189
|
-
@html_options
|
199
|
+
return @html_options || NO_OPTIONS if frozen?
|
200
|
+
@html_options ||= NO_OPTIONS.dup
|
190
201
|
end
|
191
202
|
|
192
203
|
# nested action_links are referencing a column
|
@@ -198,13 +209,32 @@ module ActiveScaffold::DataStructures
|
|
198
209
|
@keep_open
|
199
210
|
end
|
200
211
|
|
212
|
+
# for links in singular associations, copied from
|
213
|
+
# column.actions_for_association_links, excluding
|
214
|
+
# actions not available in association's controller
|
215
|
+
attr_accessor :controller_actions
|
216
|
+
|
201
217
|
# indicates that this a nested_link
|
202
218
|
def nested_link?
|
203
|
-
@column || (
|
219
|
+
@column || parameters&.dig(:named_scope)
|
204
220
|
end
|
205
221
|
|
206
222
|
def name_to_cache
|
207
|
-
@name_to_cache
|
223
|
+
return @name_to_cache if defined? @name_to_cache
|
224
|
+
[
|
225
|
+
controller || 'self',
|
226
|
+
type,
|
227
|
+
action,
|
228
|
+
*parameters.map { |k, v| "#{k}=#{v.is_a?(Array) ? v.join(',') : v}" }
|
229
|
+
].compact.join('_').tap do |name_to_cache|
|
230
|
+
@name_to_cache = name_to_cache unless frozen?
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def freeze
|
235
|
+
# force generating cache_key, except for column's link without action, or polymorphic associations
|
236
|
+
name_to_cache if action && !column&.association&.polymorphic?
|
237
|
+
super
|
208
238
|
end
|
209
239
|
end
|
210
240
|
end
|
@@ -53,8 +53,8 @@ module ActiveScaffold::DataStructures
|
|
53
53
|
if item.is_a?(ActiveScaffold::DataStructures::ActionLinks)
|
54
54
|
collected = item[val]
|
55
55
|
links << collected unless collected.nil?
|
56
|
-
|
57
|
-
links << item
|
56
|
+
elsif item.action.to_s == val.to_s
|
57
|
+
links << item
|
58
58
|
end
|
59
59
|
end
|
60
60
|
links.first
|
@@ -66,8 +66,8 @@ module ActiveScaffold::DataStructures
|
|
66
66
|
if item.is_a?(ActiveScaffold::DataStructures::ActionLinks)
|
67
67
|
collected = item.find_duplicate(link)
|
68
68
|
links << collected unless collected.nil?
|
69
|
-
|
70
|
-
links << item
|
69
|
+
elsif item.action == link.action && item.static_controller? && item.controller == link.controller && item.parameters == link.parameters
|
70
|
+
links << item
|
71
71
|
end
|
72
72
|
end
|
73
73
|
links.first
|
@@ -90,7 +90,6 @@ module ActiveScaffold::DataStructures
|
|
90
90
|
break
|
91
91
|
else
|
92
92
|
group.delete_group(name)
|
93
|
-
break
|
94
93
|
end
|
95
94
|
end
|
96
95
|
end
|
@@ -101,12 +100,10 @@ module ActiveScaffold::DataStructures
|
|
101
100
|
@set.sort_by(&:weight).send(method) do |item|
|
102
101
|
if item.is_a?(ActiveScaffold::DataStructures::ActionLinks) && !options[:groups]
|
103
102
|
item.each(options, &block)
|
103
|
+
elsif options[:include_set]
|
104
|
+
yield item, @set
|
104
105
|
else
|
105
|
-
|
106
|
-
yield item, @set
|
107
|
-
else
|
108
|
-
yield item
|
109
|
-
end
|
106
|
+
yield item
|
110
107
|
end
|
111
108
|
end
|
112
109
|
end
|
@@ -147,16 +144,21 @@ module ActiveScaffold::DataStructures
|
|
147
144
|
end
|
148
145
|
|
149
146
|
def method_missing(name, *args, &block)
|
150
|
-
|
151
|
-
|
147
|
+
return super if name =~ /[!?]$/
|
148
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
149
|
+
def #{name}(label = nil) # rubocop:disable Style/CommentedKeyword
|
152
150
|
@#{name} ||= subgroup('#{name}'.to_sym, label)
|
153
151
|
yield @#{name} if block_given?
|
154
152
|
@#{name}
|
155
153
|
end
|
156
|
-
|
154
|
+
METHOD
|
157
155
|
send(name, args.first, &block)
|
158
156
|
end
|
159
157
|
|
158
|
+
def respond_to_missing?(name, *)
|
159
|
+
name !~ /[!?]$/
|
160
|
+
end
|
161
|
+
|
160
162
|
attr_accessor :name
|
161
163
|
attr_accessor :weight
|
162
164
|
|
@@ -4,21 +4,29 @@ module ActiveScaffold::DataStructures::Association
|
|
4
4
|
@association = association
|
5
5
|
end
|
6
6
|
attr_writer :reverse
|
7
|
-
delegate :name, :
|
7
|
+
delegate :name, :foreign_key, :==, to: :@association
|
8
8
|
|
9
9
|
def allow_join?
|
10
10
|
!polymorphic?
|
11
11
|
end
|
12
12
|
|
13
|
+
def klass(record = nil)
|
14
|
+
if polymorphic?
|
15
|
+
record&.send(foreign_type)&.safe_constantize
|
16
|
+
else
|
17
|
+
@association.klass
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
13
21
|
def belongs_to?
|
14
22
|
@association.macro == :belongs_to
|
15
23
|
end
|
16
24
|
|
17
|
-
def has_one?
|
25
|
+
def has_one? # rubocop:disable Naming/PredicateName
|
18
26
|
@association.macro == :has_one
|
19
27
|
end
|
20
28
|
|
21
|
-
def has_many?
|
29
|
+
def has_many? # rubocop:disable Naming/PredicateName
|
22
30
|
@association.macro == :has_many
|
23
31
|
end
|
24
32
|
|
@@ -30,10 +38,22 @@ module ActiveScaffold::DataStructures::Association
|
|
30
38
|
!collection?
|
31
39
|
end
|
32
40
|
|
41
|
+
def collection?
|
42
|
+
has_many? || habtm?
|
43
|
+
end
|
44
|
+
|
33
45
|
def through?
|
34
46
|
false
|
35
47
|
end
|
36
48
|
|
49
|
+
def through_singular?
|
50
|
+
through? && !through_reflection.collection?
|
51
|
+
end
|
52
|
+
|
53
|
+
def through_collection?
|
54
|
+
through? && through_reflection.collection?
|
55
|
+
end
|
56
|
+
|
37
57
|
def polymorphic?
|
38
58
|
false
|
39
59
|
end
|
@@ -48,6 +68,8 @@ module ActiveScaffold::DataStructures::Association
|
|
48
68
|
|
49
69
|
def scope; end
|
50
70
|
|
71
|
+
def as; end
|
72
|
+
|
51
73
|
def respond_to_target?
|
52
74
|
false
|
53
75
|
end
|
@@ -66,23 +88,24 @@ module ActiveScaffold::DataStructures::Association
|
|
66
88
|
|
67
89
|
def reverse(klass = nil)
|
68
90
|
unless polymorphic? || defined?(@reverse)
|
69
|
-
@reverse ||= inverse || get_reverse
|
91
|
+
@reverse ||= inverse || get_reverse&.name
|
70
92
|
end
|
71
|
-
@reverse || (get_reverse(klass)
|
93
|
+
@reverse || (get_reverse(klass)&.name unless klass.nil?)
|
72
94
|
end
|
73
95
|
|
74
96
|
def inverse_for?(klass)
|
75
|
-
inverse_class = reverse_association(klass)
|
97
|
+
inverse_class = reverse_association(klass)&.inverse_klass
|
76
98
|
inverse_class.present? && (inverse_class == klass || klass < inverse_class)
|
77
99
|
end
|
78
100
|
|
79
101
|
def reverse_association(klass = nil)
|
80
|
-
assoc =
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
102
|
+
assoc =
|
103
|
+
if polymorphic?
|
104
|
+
get_reverse(klass) unless klass.nil?
|
105
|
+
else
|
106
|
+
reverse_name = reverse(klass)
|
107
|
+
reflect_on_association(reverse_name) if reverse_name
|
108
|
+
end
|
86
109
|
self.class.new(assoc) if assoc
|
87
110
|
end
|
88
111
|
|
@@ -110,13 +133,13 @@ module ActiveScaffold::DataStructures::Association
|
|
110
133
|
associations = self.class.reflect_on_all_associations(klass)
|
111
134
|
# collect associations that point back to this model and use the same foreign_key
|
112
135
|
associations.each_with_object([]) do |assoc, reverse_matches|
|
113
|
-
reverse_matches << assoc if reverse_match?
|
136
|
+
reverse_matches << assoc if assoc != @association && reverse_match?(assoc)
|
114
137
|
end
|
115
138
|
end
|
116
139
|
|
117
140
|
def reverse_match?(assoc)
|
118
|
-
return
|
119
|
-
return false
|
141
|
+
return assoc.name == as if as || assoc.polymorphic?
|
142
|
+
return false if assoc.class_name != inverse_klass&.name
|
120
143
|
|
121
144
|
if through?
|
122
145
|
reverse_through_match?(assoc)
|
@@ -17,18 +17,14 @@ module ActiveScaffold::DataStructures::Association
|
|
17
17
|
%i[belongs_to_record belongs_to_document].include?(@association.macro)
|
18
18
|
end
|
19
19
|
|
20
|
-
def has_one?
|
20
|
+
def has_one? # rubocop:disable Naming/PredicateName
|
21
21
|
%i[has_one_record has_one_document].include?(@association.macro)
|
22
22
|
end
|
23
23
|
|
24
|
-
def has_many?
|
24
|
+
def has_many? # rubocop:disable Naming/PredicateName
|
25
25
|
%i[has_many_records has_many_documents].include?(@association.macro)
|
26
26
|
end
|
27
27
|
|
28
|
-
def collection?
|
29
|
-
%i[has_many_documents has_many_records].include?(@association.macro)
|
30
|
-
end
|
31
|
-
|
32
28
|
def table_name
|
33
29
|
@association.klass < ActiveRecord::Base ? @association.klass.table_name : super
|
34
30
|
end
|
@@ -48,7 +48,7 @@ module ActiveScaffold::DataStructures::Association
|
|
48
48
|
|
49
49
|
# name of inverse
|
50
50
|
def inverse
|
51
|
-
@association.inverse_of
|
51
|
+
@association.inverse_of&.name
|
52
52
|
end
|
53
53
|
|
54
54
|
def quoted_table_name
|
@@ -75,7 +75,11 @@ module ActiveScaffold::DataStructures::Association
|
|
75
75
|
|
76
76
|
def scope_values
|
77
77
|
return {} unless @association.scope
|
78
|
-
@scope_values ||= @association.klass.instance_exec(&@association.scope).values
|
78
|
+
@scope_values ||= @association.klass.instance_exec(&@association.scope).values
|
79
|
+
rescue StandardError => e
|
80
|
+
message = "Error evaluating scope for #{@association.name} in #{@association.klass.name}:"
|
81
|
+
Rails.logger.warn "#{message}\n#{e.message}\n#{e.backtrace.join("\n")}"
|
82
|
+
{}
|
79
83
|
end
|
80
84
|
|
81
85
|
def reverse_through_match?(assoc)
|
@@ -1,9 +1,6 @@
|
|
1
1
|
module ActiveScaffold::DataStructures::Association
|
2
2
|
class Mongoid < Abstract
|
3
3
|
delegate :inverse_klass, :as, :dependent, :inverse, to: :@association
|
4
|
-
def collection?
|
5
|
-
%i[has_many has_and_belongs_to_many].include?(@association.macro)
|
6
|
-
end
|
7
4
|
|
8
5
|
# polymorphic belongs_to
|
9
6
|
def polymorphic?
|
@@ -2,12 +2,14 @@ module ActiveScaffold::DataStructures
|
|
2
2
|
class Column
|
3
3
|
include ActiveScaffold::Configurable
|
4
4
|
include ActiveScaffold::OrmChecks
|
5
|
+
NO_PARAMS = Set.new.freeze
|
6
|
+
NO_OPTIONS = {}.freeze
|
5
7
|
|
6
8
|
attr_reader :active_record_class
|
7
9
|
alias model active_record_class
|
8
10
|
|
9
11
|
# this is the name of the getter on the ActiveRecord model. it is the only absolutely required attribute ... all others will be inferred from this name.
|
10
|
-
|
12
|
+
attr_reader :name
|
11
13
|
|
12
14
|
# Whether to enable inplace editing for this column. Currently works for text columns, in the List.
|
13
15
|
attr_reader :inplace_edit
|
@@ -31,8 +33,8 @@ module ActiveScaffold::DataStructures
|
|
31
33
|
|
32
34
|
# Any extra parameters this particular column uses. This is for create/update purposes.
|
33
35
|
def params
|
34
|
-
|
35
|
-
@params ||=
|
36
|
+
return @params || NO_PARAMS if frozen?
|
37
|
+
@params ||= NO_PARAMS.dup
|
36
38
|
end
|
37
39
|
|
38
40
|
# the display-name of the column. this will be used, for instance, as the column title in the table and as the field name in the form.
|
@@ -112,16 +114,9 @@ module ActiveScaffold::DataStructures
|
|
112
114
|
# supported options:
|
113
115
|
# * for association columns
|
114
116
|
# * :select - displays a simple <select> or a collection of checkboxes to (dis)associate records
|
115
|
-
|
116
|
-
self.list_method = nil if @list_ui.nil? && value != @form_ui
|
117
|
-
@form_ui = value
|
118
|
-
end
|
119
|
-
attr_reader :form_ui
|
117
|
+
attr_accessor :form_ui
|
120
118
|
|
121
|
-
|
122
|
-
self.list_method = nil if value != @list_ui
|
123
|
-
@list_ui = value
|
124
|
-
end
|
119
|
+
attr_writer :list_ui
|
125
120
|
|
126
121
|
def list_ui
|
127
122
|
@list_ui || form_ui
|
@@ -140,10 +135,12 @@ module ActiveScaffold::DataStructures
|
|
140
135
|
# a place to store dev's column specific options
|
141
136
|
attr_writer :options
|
142
137
|
def options
|
143
|
-
@options
|
138
|
+
return @options || NO_OPTIONS if frozen?
|
139
|
+
@options ||= NO_OPTIONS.dup
|
144
140
|
end
|
145
141
|
|
146
142
|
def link
|
143
|
+
return @link.call(self) if frozen? && @link.is_a?(Proc)
|
147
144
|
@link = @link.call(self) if @link.is_a? Proc
|
148
145
|
@link
|
149
146
|
end
|
@@ -182,10 +179,11 @@ module ActiveScaffold::DataStructures
|
|
182
179
|
# a collection of associations to pre-load when finding the records on a page
|
183
180
|
attr_reader :includes
|
184
181
|
def includes=(value)
|
185
|
-
@includes =
|
186
|
-
|
187
|
-
|
188
|
-
|
182
|
+
@includes =
|
183
|
+
case value
|
184
|
+
when Array then value
|
185
|
+
else value ? [value] : value # not convert nil to [nil]
|
186
|
+
end
|
189
187
|
end
|
190
188
|
|
191
189
|
# a collection of associations to do left join when this column is included on search
|
@@ -194,10 +192,11 @@ module ActiveScaffold::DataStructures
|
|
194
192
|
end
|
195
193
|
|
196
194
|
def search_joins=(value)
|
197
|
-
@search_joins =
|
198
|
-
|
199
|
-
|
200
|
-
|
195
|
+
@search_joins =
|
196
|
+
case value
|
197
|
+
when Array then value
|
198
|
+
else [value] # automatically convert to an array
|
199
|
+
end
|
201
200
|
end
|
202
201
|
|
203
202
|
# a collection of columns to load when eager loading is disabled, if it's nil all columns will be loaded
|
@@ -210,7 +209,7 @@ module ActiveScaffold::DataStructures
|
|
210
209
|
def search_sql=(value)
|
211
210
|
@search_sql =
|
212
211
|
if value
|
213
|
-
|
212
|
+
value == true || value.is_a?(Proc) ? value : Array(value)
|
214
213
|
else
|
215
214
|
value
|
216
215
|
end
|
@@ -241,6 +240,9 @@ module ActiveScaffold::DataStructures
|
|
241
240
|
@associated_number
|
242
241
|
end
|
243
242
|
|
243
|
+
# what string to use to join records from plural associations
|
244
|
+
attr_accessor :association_join_text
|
245
|
+
|
244
246
|
# whether a blank row must be shown in the subform
|
245
247
|
cattr_accessor :show_blank_record, instance_accessor: false
|
246
248
|
@@show_blank_record = true
|
@@ -300,21 +302,26 @@ module ActiveScaffold::DataStructures
|
|
300
302
|
end
|
301
303
|
end
|
302
304
|
|
305
|
+
# cache key to cache column info
|
306
|
+
attr_reader :cache_key
|
307
|
+
|
303
308
|
# instantiation is handled internally through the DataStructures::Columns object
|
304
309
|
def initialize(name, active_record_class, delegated_association = nil) #:nodoc:
|
305
|
-
|
310
|
+
@name = name.to_sym
|
306
311
|
@active_record_class = active_record_class
|
307
|
-
@column = _columns_hash[
|
312
|
+
@column = _columns_hash[name.to_s]
|
308
313
|
@delegated_association = delegated_association
|
314
|
+
@cache_key = [@active_record_class.name, name].compact.map(&:to_s).join('#')
|
309
315
|
setup_association_info
|
310
316
|
|
311
|
-
@
|
317
|
+
@link = nil
|
318
|
+
@autolink = association.present?
|
312
319
|
@table = _table_name
|
313
320
|
@associated_limit = self.class.associated_limit
|
314
321
|
@associated_number = self.class.associated_number
|
315
322
|
@show_blank_record = self.class.show_blank_record
|
316
323
|
@send_form_on_update_column = self.class.send_form_on_update_column
|
317
|
-
@actions_for_association_links = self.class.actions_for_association_links.
|
324
|
+
@actions_for_association_links = self.class.actions_for_association_links.dup if association
|
318
325
|
@select_columns = default_select_columns
|
319
326
|
|
320
327
|
@text = @column.nil? || [:string, :text, String].include?(column_type)
|
@@ -328,16 +335,17 @@ module ActiveScaffold::DataStructures
|
|
328
335
|
@form_ui = :number
|
329
336
|
@options = {:format => :i18n_number}
|
330
337
|
else
|
331
|
-
@form_ui =
|
332
|
-
|
333
|
-
|
334
|
-
|
338
|
+
@form_ui =
|
339
|
+
case @column.type
|
340
|
+
when :boolean then :checkbox
|
341
|
+
when :text then :textarea
|
342
|
+
end
|
335
343
|
end
|
336
344
|
end
|
337
345
|
@allow_add_existing = true
|
338
346
|
@form_ui = self.class.association_form_ui if @association && self.class.association_form_ui
|
339
347
|
|
340
|
-
self.includes = [association.name] if association
|
348
|
+
self.includes = [association.name] if association&.allow_join?
|
341
349
|
if delegated_association
|
342
350
|
self.includes = includes ? [delegated_association.name => includes] : [delegated_association.name]
|
343
351
|
end
|
@@ -345,7 +353,7 @@ module ActiveScaffold::DataStructures
|
|
345
353
|
|
346
354
|
# default all the configurable variables
|
347
355
|
self.css_class = ''
|
348
|
-
self.required = active_record_class.validators_on(
|
356
|
+
self.required = active_record_class.validators_on(name).any? do |val|
|
349
357
|
validator_force_required?(val)
|
350
358
|
end
|
351
359
|
self.sort = true
|
@@ -365,18 +373,23 @@ module ActiveScaffold::DataStructures
|
|
365
373
|
order_weight.nonzero? ? order_weight : name.to_s <=> other.name.to_s
|
366
374
|
end
|
367
375
|
|
376
|
+
def convert_to_native?
|
377
|
+
number? && options[:format] && form_ui != :number
|
378
|
+
end
|
379
|
+
|
368
380
|
def number_to_native(value)
|
369
381
|
return value if value.blank? || !value.is_a?(String)
|
370
382
|
native = '.' # native ruby separator
|
371
383
|
format = {:separator => '', :delimiter => ''}.merge! I18n.t('number.format', :default => {})
|
372
|
-
specific =
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
384
|
+
specific =
|
385
|
+
case options[:format]
|
386
|
+
when :currency
|
387
|
+
I18n.t('number.currency.format', :default => nil)
|
388
|
+
when :size
|
389
|
+
I18n.t('number.human.format', :default => nil)
|
390
|
+
when :percentage
|
391
|
+
I18n.t('number.percentage.format', :default => nil)
|
392
|
+
end
|
380
393
|
format.merge! specific unless specific.nil?
|
381
394
|
if format[:separator].blank? || !value.include?(format[:separator]) && value.include?(native) && (format[:delimiter] != native || value !~ /\.\d{3}$/)
|
382
395
|
value
|
@@ -385,11 +398,9 @@ module ActiveScaffold::DataStructures
|
|
385
398
|
end
|
386
399
|
end
|
387
400
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
# cache constraints for numeric columns (get in ActiveScaffold::Helpers::FormColumnHelpers::numerical_constraints_for_column)
|
392
|
-
attr_accessor :numerical_constraints
|
401
|
+
def default_for_empty_value
|
402
|
+
(column.null ? nil : column.default) if column
|
403
|
+
end
|
393
404
|
|
394
405
|
# the table.field name for this column, if applicable
|
395
406
|
def field
|
@@ -407,16 +418,18 @@ module ActiveScaffold::DataStructures
|
|
407
418
|
protected
|
408
419
|
|
409
420
|
def setup_association_info
|
410
|
-
assoc = active_record_class.reflect_on_association(
|
411
|
-
@association =
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
421
|
+
assoc = active_record_class.reflect_on_association(name)
|
422
|
+
@association =
|
423
|
+
if assoc
|
424
|
+
if active_record?
|
425
|
+
Association::ActiveRecord.new(assoc)
|
426
|
+
elsif mongoid?
|
427
|
+
Association::Mongoid.new(assoc)
|
428
|
+
end
|
429
|
+
elsif defined?(ActiveMongoid) && model < ActiveMongoid::Associations
|
430
|
+
assoc = active_record_class.reflect_on_am_association(name)
|
431
|
+
Association::ActiveMongoid.new(assoc) if assoc
|
432
|
+
end
|
420
433
|
end
|
421
434
|
|
422
435
|
def validator_force_required?(val)
|
@@ -438,7 +451,7 @@ module ActiveScaffold::DataStructures
|
|
438
451
|
def default_select_columns
|
439
452
|
if association.nil? && column
|
440
453
|
[field]
|
441
|
-
elsif association
|
454
|
+
elsif association&.polymorphic?
|
442
455
|
[field, quoted_field(quoted_field_name(association.foreign_type))]
|
443
456
|
elsif association
|
444
457
|
if association.belongs_to?
|
@@ -448,7 +461,7 @@ module ActiveScaffold::DataStructures
|
|
448
461
|
if _columns_hash[count_column = "#{association.name}_count"]
|
449
462
|
columns << quoted_field(quoted_field_name(count_column))
|
450
463
|
end
|
451
|
-
if association.through_reflection
|
464
|
+
if association.through_reflection&.belongs_to?
|
452
465
|
columns << quoted_field(quoted_field_name(association.through_reflection.foreign_key))
|
453
466
|
end
|
454
467
|
columns
|
@@ -474,16 +487,12 @@ module ActiveScaffold::DataStructures
|
|
474
487
|
end
|
475
488
|
|
476
489
|
def initialize_sort
|
477
|
-
|
478
|
-
# we don't automatically enable method sorting for virtual columns because it's slow, and we expect fewer complaints this way.
|
479
|
-
self.sort = false
|
480
|
-
else
|
490
|
+
self.sort =
|
481
491
|
if column && !tableless?
|
482
|
-
|
492
|
+
{:sql => field}
|
483
493
|
else
|
484
|
-
|
494
|
+
false
|
485
495
|
end
|
486
|
-
end
|
487
496
|
end
|
488
497
|
|
489
498
|
def initialize_search_sql
|
@@ -501,9 +510,9 @@ module ActiveScaffold::DataStructures
|
|
501
510
|
attr_reader :table
|
502
511
|
|
503
512
|
def estimate_weight
|
504
|
-
if association
|
513
|
+
if association&.singular?
|
505
514
|
400
|
506
|
-
elsif association
|
515
|
+
elsif association&.collection?
|
507
516
|
500
|
508
517
|
elsif %i[created_at updated_at].include?(name)
|
509
518
|
600
|