active_scaffold 3.5.2 → 3.6.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{CHANGELOG → CHANGELOG.rdoc} +66 -0
- data/README.md +17 -7
- data/app/assets/javascripts/active_scaffold.js.erb +0 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +63 -6
- data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
- data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
- data/app/views/active_scaffold_overrides/_base_form.html.erb +2 -2
- data/app/views/active_scaffold_overrides/_form.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +3 -2
- data/app/views/active_scaffold_overrides/_form_association_record.html.erb +6 -6
- data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_list.html.erb +2 -1
- data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
- data/app/views/active_scaffold_overrides/_list_messages.html.erb +1 -0
- data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
- data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_messages.html.erb +1 -0
- data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
- data/app/views/active_scaffold_overrides/_render_field.js.erb +2 -1
- data/app/views/active_scaffold_overrides/_show_association_horizontal.html.erb +2 -1
- data/app/views/active_scaffold_overrides/_show_columns.html.erb +2 -2
- data/app/views/active_scaffold_overrides/_show_horizontal_record.html.erb +4 -4
- data/app/views/active_scaffold_overrides/_update_calculations.js.erb +1 -1
- data/app/views/active_scaffold_overrides/_update_column.js.erb +2 -2
- data/app/views/active_scaffold_overrides/action_confirmation.html.erb +2 -2
- data/app/views/active_scaffold_overrides/delete.html.erb +2 -2
- data/app/views/active_scaffold_overrides/on_action_update.js.erb +16 -6
- data/app/views/active_scaffold_overrides/on_update.js.erb +1 -1
- data/app/views/active_scaffold_overrides/row.js.erb +1 -1
- data/app/views/active_scaffold_overrides/update_column.js.erb +1 -1
- data/config/locales/de.yml +2 -1
- data/config/locales/en.yml +1 -0
- data/config/locales/es.yml +1 -0
- data/config/locales/fr.yml +2 -1
- data/config/locales/hu.yml +1 -0
- data/config/locales/ja.yml +1 -0
- data/config/locales/ru.yml +1 -0
- data/lib/active_scaffold.rb +19 -16
- data/lib/active_scaffold/actions/common_search.rb +11 -8
- data/lib/active_scaffold/actions/core.rb +89 -71
- data/lib/active_scaffold/actions/create.rb +28 -28
- data/lib/active_scaffold/actions/delete.rb +3 -3
- data/lib/active_scaffold/actions/field_search.rb +53 -43
- data/lib/active_scaffold/actions/list.rb +111 -27
- data/lib/active_scaffold/actions/nested.rb +65 -48
- data/lib/active_scaffold/actions/search.rb +1 -1
- data/lib/active_scaffold/actions/show.rb +4 -4
- data/lib/active_scaffold/actions/subform.rb +12 -17
- data/lib/active_scaffold/actions/update.rb +96 -77
- data/lib/active_scaffold/active_record_permissions.rb +2 -11
- data/lib/active_scaffold/attribute_params.rb +104 -86
- data/lib/active_scaffold/bridges.rb +8 -8
- data/lib/active_scaffold/bridges/active_storage.rb +6 -0
- data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +33 -0
- data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
- data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
- data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
- data/lib/active_scaffold/bridges/bitfields.rb +1 -0
- data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
- data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -12
- data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
- data/lib/active_scaffold/bridges/chosen/helpers.rb +11 -9
- data/lib/active_scaffold/bridges/date_picker/ext.rb +0 -13
- data/lib/active_scaffold/bridges/date_picker/helper.rb +49 -44
- data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +3 -3
- data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
- data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +10 -7
- data/lib/active_scaffold/bridges/paper_trail.rb +1 -1
- data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
- data/lib/active_scaffold/bridges/record_select/helpers.rb +12 -16
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -19
- data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
- data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +21 -4
- data/lib/active_scaffold/config/base.rb +133 -41
- data/lib/active_scaffold/config/core.rb +146 -18
- data/lib/active_scaffold/config/delete.rb +14 -1
- data/lib/active_scaffold/config/field_search.rb +7 -1
- data/lib/active_scaffold/config/form.rb +10 -1
- data/lib/active_scaffold/config/list.rb +39 -13
- data/lib/active_scaffold/config/mark.rb +4 -2
- data/lib/active_scaffold/config/nested.rb +16 -17
- data/lib/active_scaffold/config/search.rb +9 -0
- data/lib/active_scaffold/config/show.rb +4 -0
- data/lib/active_scaffold/config/update.rb +4 -0
- data/lib/active_scaffold/configurable.rb +14 -7
- data/lib/active_scaffold/constraints.rb +22 -20
- data/lib/active_scaffold/core.rb +68 -29
- data/lib/active_scaffold/data_structures/action_columns.rb +50 -59
- data/lib/active_scaffold/data_structures/action_link.rb +50 -20
- data/lib/active_scaffold/data_structures/action_links.rb +15 -13
- data/lib/active_scaffold/data_structures/association/abstract.rb +41 -15
- data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
- data/lib/active_scaffold/data_structures/association/active_record.rb +6 -2
- data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
- data/lib/active_scaffold/data_structures/column.rb +75 -66
- data/lib/active_scaffold/data_structures/columns.rb +3 -2
- data/lib/active_scaffold/data_structures/nested_info.rb +21 -19
- data/lib/active_scaffold/data_structures/set.rb +8 -0
- data/lib/active_scaffold/data_structures/sorting.rb +10 -2
- data/lib/active_scaffold/delayed_setup.rb +16 -5
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +3 -2
- data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
- data/lib/active_scaffold/extensions/cow_proxy.rb +91 -0
- data/lib/active_scaffold/extensions/ice_nine.rb +36 -0
- data/lib/active_scaffold/extensions/left_outer_joins.rb +8 -33
- data/lib/active_scaffold/extensions/localize.rb +3 -1
- data/lib/active_scaffold/extensions/routing_mapper.rb +6 -45
- data/lib/active_scaffold/extensions/to_label.rb +3 -2
- data/lib/active_scaffold/extensions/unsaved_record.rb +2 -4
- data/lib/active_scaffold/finder.rb +104 -73
- data/lib/active_scaffold/helpers/action_link_helpers.rb +62 -36
- data/lib/active_scaffold/helpers/association_helpers.rb +21 -19
- data/lib/active_scaffold/helpers/controller_helpers.rb +23 -10
- data/lib/active_scaffold/helpers/form_column_helpers.rb +157 -121
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
- data/lib/active_scaffold/helpers/id_helpers.rb +6 -2
- data/lib/active_scaffold/helpers/list_column_helpers.rb +82 -53
- data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
- data/lib/active_scaffold/helpers/search_column_helpers.rb +29 -34
- data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
- data/lib/active_scaffold/helpers/view_helpers.rb +38 -35
- data/lib/active_scaffold/marked_model.rb +2 -2
- data/lib/active_scaffold/orm_checks.rb +3 -7
- data/lib/active_scaffold/paginator.rb +7 -7
- data/lib/active_scaffold/registry.rb +33 -0
- data/lib/active_scaffold/responds_to_parent.rb +8 -11
- data/lib/active_scaffold/tableless.rb +67 -65
- data/lib/active_scaffold/version.rb +2 -2
- data/lib/generators/active_scaffold/controller_generator.rb +2 -2
- data/lib/generators/active_scaffold/install_generator.rb +1 -1
- data/lib/generators/active_scaffold/resource_generator.rb +2 -2
- data/shoulda_macros/macros.rb +3 -1
- data/test/bridges/date_picker_test.rb +1 -2
- data/test/bridges/paperclip_test.rb +6 -6
- data/test/class_with_finder.rb +2 -2
- data/test/company.rb +4 -4
- data/test/config/create_test.rb +4 -2
- data/test/config/nested_test.rb +1 -1
- data/test/config/show_test.rb +1 -1
- data/test/config/update_test.rb +7 -6
- data/test/data_structures/action_columns_test.rb +2 -2
- data/test/data_structures/action_links_test.rb +1 -1
- data/test/data_structures/column_test.rb +3 -6
- data/test/data_structures/columns_test.rb +2 -2
- data/test/data_structures/sorting_test.rb +7 -0
- data/test/extensions/active_record_test.rb +4 -4
- data/test/extensions/routing_mapper_test.rb +2 -2
- data/test/helpers/list_column_helpers_test.rb +3 -1
- data/test/misc/active_record_permissions_test.rb +3 -11
- data/test/misc/attribute_params_test.rb +12 -8
- data/test/misc/calculation_test.rb +1 -1
- data/test/misc/configurable_test.rb +10 -10
- data/test/misc/constraints_test.rb +2 -2
- data/test/misc/convert_numbers_format_test.rb +7 -3
- data/test/misc/lang_test.rb +1 -1
- data/test/misc/parse_datetime_test.rb +3 -4
- data/test/misc/tableless_test.rb +6 -0
- data/test/mock_app/Rakefile +1 -1
- data/test/mock_app/app/assets/config/manifest.js +0 -0
- data/test/mock_app/app/controllers/cars_controller.rb +1 -0
- data/test/mock_app/app/controllers/people_controller.rb +3 -1
- data/test/mock_app/config/application.rb +2 -1
- data/test/mock_app/config/boot.rb +1 -1
- data/test/mock_app/config/environment.rb +2 -2
- data/test/mock_app/config/routes.rb +4 -1
- data/test/mock_app/db/schema.rb +2 -0
- data/test/performance/list_cars_performance_test.rb +34 -0
- data/test/performance/list_people_performance_test.rb +31 -0
- data/test/performance_test_help.rb +3 -0
- data/test/test_helper.rb +10 -2
- metadata +56 -15
- data/app/assets/javascripts/prototype/rico_corner.js +0 -370
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -7
@@ -1,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,32 @@ 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)&.constantize
|
16
|
+
else
|
17
|
+
@association.klass
|
18
|
+
end
|
19
|
+
rescue NameError => e
|
20
|
+
Rails.logger.warn "#{e.message}\n#{e.backtrace.join("\n")}"
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
13
24
|
def belongs_to?
|
14
25
|
@association.macro == :belongs_to
|
15
26
|
end
|
16
27
|
|
17
|
-
def has_one?
|
28
|
+
def has_one? # rubocop:disable Naming/PredicateName
|
18
29
|
@association.macro == :has_one
|
19
30
|
end
|
20
31
|
|
21
|
-
def has_many?
|
32
|
+
def has_many? # rubocop:disable Naming/PredicateName
|
22
33
|
@association.macro == :has_many
|
23
34
|
end
|
24
35
|
|
@@ -30,10 +41,22 @@ module ActiveScaffold::DataStructures::Association
|
|
30
41
|
!collection?
|
31
42
|
end
|
32
43
|
|
44
|
+
def collection?
|
45
|
+
has_many? || habtm?
|
46
|
+
end
|
47
|
+
|
33
48
|
def through?
|
34
49
|
false
|
35
50
|
end
|
36
51
|
|
52
|
+
def through_singular?
|
53
|
+
through? && !through_reflection.collection?
|
54
|
+
end
|
55
|
+
|
56
|
+
def through_collection?
|
57
|
+
through? && through_reflection.collection?
|
58
|
+
end
|
59
|
+
|
37
60
|
def polymorphic?
|
38
61
|
false
|
39
62
|
end
|
@@ -48,6 +71,8 @@ module ActiveScaffold::DataStructures::Association
|
|
48
71
|
|
49
72
|
def scope; end
|
50
73
|
|
74
|
+
def as; end
|
75
|
+
|
51
76
|
def respond_to_target?
|
52
77
|
false
|
53
78
|
end
|
@@ -66,23 +91,24 @@ module ActiveScaffold::DataStructures::Association
|
|
66
91
|
|
67
92
|
def reverse(klass = nil)
|
68
93
|
unless polymorphic? || defined?(@reverse)
|
69
|
-
@reverse ||= inverse || get_reverse
|
94
|
+
@reverse ||= inverse || get_reverse&.name
|
70
95
|
end
|
71
|
-
@reverse || (get_reverse(klass)
|
96
|
+
@reverse || (get_reverse(klass)&.name unless klass.nil?)
|
72
97
|
end
|
73
98
|
|
74
99
|
def inverse_for?(klass)
|
75
|
-
inverse_class = reverse_association(klass)
|
100
|
+
inverse_class = reverse_association(klass)&.inverse_klass
|
76
101
|
inverse_class.present? && (inverse_class == klass || klass < inverse_class)
|
77
102
|
end
|
78
103
|
|
79
104
|
def reverse_association(klass = nil)
|
80
|
-
assoc =
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
105
|
+
assoc =
|
106
|
+
if polymorphic?
|
107
|
+
get_reverse(klass) unless klass.nil?
|
108
|
+
else
|
109
|
+
reverse_name = reverse(klass)
|
110
|
+
reflect_on_association(reverse_name) if reverse_name
|
111
|
+
end
|
86
112
|
self.class.new(assoc) if assoc
|
87
113
|
end
|
88
114
|
|
@@ -110,13 +136,13 @@ module ActiveScaffold::DataStructures::Association
|
|
110
136
|
associations = self.class.reflect_on_all_associations(klass)
|
111
137
|
# collect associations that point back to this model and use the same foreign_key
|
112
138
|
associations.each_with_object([]) do |assoc, reverse_matches|
|
113
|
-
reverse_matches << assoc if reverse_match?
|
139
|
+
reverse_matches << assoc if assoc != @association && reverse_match?(assoc)
|
114
140
|
end
|
115
141
|
end
|
116
142
|
|
117
143
|
def reverse_match?(assoc)
|
118
|
-
return
|
119
|
-
return false
|
144
|
+
return assoc.name == as if as || assoc.polymorphic?
|
145
|
+
return false if assoc.class_name != inverse_klass&.name
|
120
146
|
|
121
147
|
if through?
|
122
148
|
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
|