rails_admin 3.1.1 → 3.3.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/Gemfile +23 -17
- data/README.md +6 -4
- data/app/assets/javascripts/rails_admin/application.js.erb +3 -2
- data/app/assets/stylesheets/rails_admin/application.scss.erb +1 -1
- data/app/controllers/rails_admin/main_controller.rb +16 -1
- data/app/helpers/rails_admin/application_helper.rb +4 -0
- data/app/helpers/rails_admin/form_builder.rb +6 -5
- data/app/helpers/rails_admin/main_helper.rb +1 -1
- data/app/views/layouts/rails_admin/_head.html.erb +10 -7
- data/app/views/rails_admin/main/_form_boolean.html.erb +2 -2
- data/app/views/rails_admin/main/_form_filtering_multiselect.html.erb +5 -35
- data/app/views/rails_admin/main/_form_filtering_select.html.erb +6 -18
- data/app/views/rails_admin/main/_form_nested_many.html.erb +1 -1
- data/app/views/rails_admin/main/_form_nested_one.html.erb +1 -1
- data/app/views/rails_admin/main/_form_polymorphic_association.html.erb +12 -21
- data/app/views/rails_admin/main/delete.html.erb +1 -1
- data/app/views/rails_admin/main/index.html.erb +2 -2
- data/config/initializers/active_record_extensions.rb +0 -23
- data/lib/generators/rails_admin/importmap_formatter.rb +3 -2
- data/lib/generators/rails_admin/install_generator.rb +13 -1
- data/lib/generators/rails_admin/templates/rails_admin.vite.js +2 -0
- data/lib/rails_admin/abstract_model.rb +18 -7
- data/lib/rails_admin/adapters/active_record/association.rb +28 -11
- data/lib/rails_admin/adapters/active_record/object_extension.rb +0 -18
- data/lib/rails_admin/adapters/active_record.rb +56 -5
- data/lib/rails_admin/adapters/mongoid/association.rb +4 -4
- data/lib/rails_admin/adapters/mongoid/bson.rb +1 -0
- data/lib/rails_admin/adapters/mongoid/object_extension.rb +0 -5
- data/lib/rails_admin/adapters/mongoid.rb +13 -3
- data/lib/rails_admin/config/actions/export.rb +2 -1
- data/lib/rails_admin/config/actions/index.rb +7 -5
- data/lib/rails_admin/config/actions/show.rb +1 -1
- data/lib/rails_admin/config/configurable.rb +1 -1
- data/lib/rails_admin/config/fields/association.rb +41 -2
- data/lib/rails_admin/config/fields/base.rb +5 -5
- data/lib/rails_admin/config/fields/collection_association.rb +90 -0
- data/lib/rails_admin/config/fields/factories/active_storage.rb +2 -2
- data/lib/rails_admin/config/fields/factories/carrierwave.rb +1 -1
- data/lib/rails_admin/config/fields/factories/dragonfly.rb +1 -1
- data/lib/rails_admin/config/fields/factories/paperclip.rb +1 -1
- data/lib/rails_admin/config/fields/factories/shrine.rb +1 -1
- data/lib/rails_admin/config/fields/singular_association.rb +59 -0
- data/lib/rails_admin/config/fields/types/active_storage.rb +12 -7
- data/lib/rails_admin/config/fields/types/all.rb +0 -1
- data/lib/rails_admin/config/fields/types/belongs_to_association.rb +17 -20
- data/lib/rails_admin/config/fields/types/dragonfly.rb +0 -1
- data/lib/rails_admin/config/fields/types/file_upload.rb +7 -1
- data/lib/rails_admin/config/fields/types/has_and_belongs_to_many_association.rb +2 -2
- data/lib/rails_admin/config/fields/types/has_many_association.rb +2 -24
- data/lib/rails_admin/config/fields/types/has_one_association.rb +12 -22
- data/lib/rails_admin/config/fields/types/multiple_active_storage.rb +13 -8
- data/lib/rails_admin/config/fields/types/multiple_file_upload.rb +7 -1
- data/lib/rails_admin/config/fields/types/polymorphic_association.rb +32 -9
- data/lib/rails_admin/config/model.rb +3 -1
- data/lib/rails_admin/config.rb +9 -5
- data/lib/rails_admin/engine.rb +5 -0
- data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +1 -1
- data/lib/rails_admin/extensions/pundit/authorization_adapter.rb +2 -1
- data/lib/rails_admin/extensions/url_for_extension.rb +15 -0
- data/lib/rails_admin/support/composite_keys_serializer.rb +15 -0
- data/lib/rails_admin/support/csv_converter.rb +0 -1
- data/lib/rails_admin/support/datetime.rb +1 -0
- data/lib/rails_admin/support/serialization_schema.rb +72 -0
- data/lib/rails_admin/version.rb +1 -1
- data/lib/rails_admin.rb +1 -0
- data/package.json +2 -2
- data/src/rails_admin/abstract-select.js +30 -0
- data/src/rails_admin/base.js +4 -1
- data/src/rails_admin/filtering-multiselect.js +2 -4
- data/src/rails_admin/filtering-select.js +2 -4
- data/src/rails_admin/ui.js +7 -1
- metadata +41 -18
- data/lib/rails_admin/adapters/composite_primary_keys/association.rb +0 -45
- data/lib/rails_admin/adapters/composite_primary_keys.rb +0 -40
- data/lib/rails_admin/config/fields/types/composite_keys_belongs_to_association.rb +0 -31
|
@@ -33,7 +33,7 @@ module RailsAdmin
|
|
|
33
33
|
|
|
34
34
|
def klass
|
|
35
35
|
if options[:polymorphic]
|
|
36
|
-
polymorphic_parents(:active_record,
|
|
36
|
+
polymorphic_parents(:active_record, association.active_record.name.to_s, name) || []
|
|
37
37
|
else
|
|
38
38
|
association.klass
|
|
39
39
|
end
|
|
@@ -42,16 +42,29 @@ module RailsAdmin
|
|
|
42
42
|
def primary_key
|
|
43
43
|
return nil if polymorphic?
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
value =
|
|
46
|
+
case type
|
|
47
|
+
when :has_one
|
|
48
|
+
association.klass.primary_key
|
|
49
|
+
else
|
|
50
|
+
association.association_primary_key
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if value.is_a? Array
|
|
54
|
+
:id
|
|
48
55
|
else
|
|
49
|
-
|
|
50
|
-
end
|
|
56
|
+
value.to_sym
|
|
57
|
+
end
|
|
51
58
|
end
|
|
52
59
|
|
|
53
60
|
def foreign_key
|
|
54
|
-
association.
|
|
61
|
+
if association.options[:query_constraints].present?
|
|
62
|
+
association.options[:query_constraints].map(&:to_sym)
|
|
63
|
+
elsif association.foreign_key.is_a?(Array)
|
|
64
|
+
association.foreign_key.map(&:to_sym)
|
|
65
|
+
else
|
|
66
|
+
association.foreign_key.to_sym
|
|
67
|
+
end
|
|
55
68
|
end
|
|
56
69
|
|
|
57
70
|
def foreign_key_nullable?
|
|
@@ -71,11 +84,15 @@ module RailsAdmin
|
|
|
71
84
|
def key_accessor
|
|
72
85
|
case type
|
|
73
86
|
when :has_many, :has_and_belongs_to_many
|
|
74
|
-
"#{name.to_s.singularize}_ids"
|
|
87
|
+
:"#{name.to_s.singularize}_ids"
|
|
75
88
|
when :has_one
|
|
76
|
-
"#{name}_id"
|
|
89
|
+
:"#{name}_id"
|
|
77
90
|
else
|
|
78
|
-
foreign_key
|
|
91
|
+
if foreign_key.is_a?(Array)
|
|
92
|
+
:"#{name}_id"
|
|
93
|
+
else
|
|
94
|
+
foreign_key
|
|
95
|
+
end
|
|
79
96
|
end
|
|
80
97
|
end
|
|
81
98
|
|
|
@@ -88,7 +105,7 @@ module RailsAdmin
|
|
|
88
105
|
end
|
|
89
106
|
|
|
90
107
|
def inverse_of
|
|
91
|
-
options[:inverse_of].try
|
|
108
|
+
options[:inverse_of].try(:to_sym) || as
|
|
92
109
|
end
|
|
93
110
|
|
|
94
111
|
def read_only?
|
|
@@ -4,24 +4,6 @@ module RailsAdmin
|
|
|
4
4
|
module Adapters
|
|
5
5
|
module ActiveRecord
|
|
6
6
|
module ObjectExtension
|
|
7
|
-
def self.extended(object)
|
|
8
|
-
object.class.reflect_on_all_associations.each do |association|
|
|
9
|
-
association = Association.new(association, object.class)
|
|
10
|
-
case association.type
|
|
11
|
-
when :has_one
|
|
12
|
-
object.instance_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
13
|
-
def #{association.name}_id
|
|
14
|
-
self.#{association.name}&.id
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def #{association.name}_id=(item_id)
|
|
18
|
-
self.#{association.name} = (#{association.klass}.find(item_id) rescue nil)
|
|
19
|
-
end
|
|
20
|
-
RUBY
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
7
|
def assign_attributes(attributes)
|
|
26
8
|
super if attributes
|
|
27
9
|
end
|
|
@@ -15,7 +15,7 @@ module RailsAdmin
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def get(id, scope = scoped)
|
|
18
|
-
object = scope
|
|
18
|
+
object = primary_key_scope(scope, id).first
|
|
19
19
|
return unless object
|
|
20
20
|
|
|
21
21
|
object.extend(ObjectExtension)
|
|
@@ -25,6 +25,10 @@ module RailsAdmin
|
|
|
25
25
|
model.all
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
def none
|
|
29
|
+
model.none
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
def first(options = {}, scope = nil)
|
|
29
33
|
all(options, scope).first
|
|
30
34
|
end
|
|
@@ -72,6 +76,14 @@ module RailsAdmin
|
|
|
72
76
|
|
|
73
77
|
delegate :primary_key, :table_name, to: :model, prefix: false
|
|
74
78
|
|
|
79
|
+
def quoted_table_name
|
|
80
|
+
model.quoted_table_name
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def quote_column_name(name)
|
|
84
|
+
model.connection.quote_column_name(name)
|
|
85
|
+
end
|
|
86
|
+
|
|
75
87
|
def encoding
|
|
76
88
|
adapter =
|
|
77
89
|
if ::ActiveRecord::Base.respond_to?(:connection_db_config)
|
|
@@ -107,10 +119,42 @@ module RailsAdmin
|
|
|
107
119
|
true
|
|
108
120
|
end
|
|
109
121
|
|
|
122
|
+
def format_id(id)
|
|
123
|
+
if primary_key.is_a? Array
|
|
124
|
+
RailsAdmin.config.composite_keys_serializer.serialize(id)
|
|
125
|
+
else
|
|
126
|
+
id
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def parse_id(id)
|
|
131
|
+
if primary_key.is_a?(Array)
|
|
132
|
+
ids = RailsAdmin.config.composite_keys_serializer.deserialize(id)
|
|
133
|
+
primary_key.each_with_index do |key, i|
|
|
134
|
+
ids[i] = model.type_for_attribute(key).cast(ids[i])
|
|
135
|
+
end
|
|
136
|
+
ids
|
|
137
|
+
else
|
|
138
|
+
id
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
110
142
|
private
|
|
111
143
|
|
|
144
|
+
def primary_key_scope(scope, id)
|
|
145
|
+
if primary_key.is_a? Array
|
|
146
|
+
scope.where(primary_key.zip(parse_id(id)).to_h)
|
|
147
|
+
else
|
|
148
|
+
scope.where(primary_key => id)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
112
152
|
def bulk_scope(scope, options)
|
|
113
|
-
|
|
153
|
+
if primary_key.is_a? Array
|
|
154
|
+
options[:bulk_ids].map { |id| primary_key_scope(scope, id) }.reduce(&:or)
|
|
155
|
+
else
|
|
156
|
+
scope.where(primary_key => options[:bulk_ids])
|
|
157
|
+
end
|
|
114
158
|
end
|
|
115
159
|
|
|
116
160
|
def sort_scope(scope, options)
|
|
@@ -172,7 +216,7 @@ module RailsAdmin
|
|
|
172
216
|
# "0055" is the filter index, no use here. o is the operator, v the value
|
|
173
217
|
def filter_scope(scope, filters, fields = config.list.fields.select(&:filterable?))
|
|
174
218
|
filters.each_pair do |field_name, filters_dump|
|
|
175
|
-
filters_dump.
|
|
219
|
+
filters_dump.each_value do |filter_dump|
|
|
176
220
|
wb = WhereBuilder.new(scope)
|
|
177
221
|
field = fields.detect { |f| f.name.to_s == field_name }
|
|
178
222
|
value = parse_field_value(field, filter_dump[:v])
|
|
@@ -201,6 +245,8 @@ module RailsAdmin
|
|
|
201
245
|
case @type
|
|
202
246
|
when :boolean
|
|
203
247
|
boolean_unary_operators
|
|
248
|
+
when :uuid
|
|
249
|
+
uuid_unary_operators
|
|
204
250
|
when :integer, :decimal, :float
|
|
205
251
|
numeric_unary_operators
|
|
206
252
|
else
|
|
@@ -230,6 +276,7 @@ module RailsAdmin
|
|
|
230
276
|
)
|
|
231
277
|
end
|
|
232
278
|
alias_method :numeric_unary_operators, :boolean_unary_operators
|
|
279
|
+
alias_method :uuid_unary_operators, :boolean_unary_operators
|
|
233
280
|
|
|
234
281
|
def range_filter(min, max)
|
|
235
282
|
if min && max && min == max
|
|
@@ -255,8 +302,12 @@ module RailsAdmin
|
|
|
255
302
|
end
|
|
256
303
|
|
|
257
304
|
def build_statement_for_boolean
|
|
258
|
-
|
|
259
|
-
|
|
305
|
+
case @value
|
|
306
|
+
when 'false', 'f', '0'
|
|
307
|
+
["(#{@column} IS NULL OR #{@column} = ?)", false]
|
|
308
|
+
when 'true', 't', '1'
|
|
309
|
+
["(#{@column} = ?)", true]
|
|
310
|
+
end
|
|
260
311
|
end
|
|
261
312
|
|
|
262
313
|
def column_for_value(value)
|
|
@@ -46,7 +46,7 @@ module RailsAdmin
|
|
|
46
46
|
|
|
47
47
|
def klass
|
|
48
48
|
if polymorphic? && %i[referenced_in belongs_to].include?(macro)
|
|
49
|
-
polymorphic_parents(:mongoid,
|
|
49
|
+
polymorphic_parents(:mongoid, association.inverse_class_name, name) || []
|
|
50
50
|
else
|
|
51
51
|
association.klass
|
|
52
52
|
end
|
|
@@ -92,9 +92,9 @@ module RailsAdmin
|
|
|
92
92
|
def key_accessor
|
|
93
93
|
case macro.to_sym
|
|
94
94
|
when :has_many
|
|
95
|
-
"#{name.to_s.singularize}_ids"
|
|
95
|
+
:"#{name.to_s.singularize}_ids"
|
|
96
96
|
when :has_one
|
|
97
|
-
"#{name}_id"
|
|
97
|
+
:"#{name}_id"
|
|
98
98
|
when :embedded_in, :embeds_one, :embeds_many
|
|
99
99
|
nil
|
|
100
100
|
else
|
|
@@ -111,7 +111,7 @@ module RailsAdmin
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def inverse_of
|
|
114
|
-
association.inverse_of.try
|
|
114
|
+
association.inverse_of.try(:to_sym) || as
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def read_only?
|
|
@@ -31,6 +31,7 @@ module RailsAdmin
|
|
|
31
31
|
Mongoid::Errors::InvalidFind
|
|
32
32
|
Moped::Errors::InvalidObjectId
|
|
33
33
|
BSON::InvalidObjectId
|
|
34
|
+
BSON::Error::InvalidObjectId
|
|
34
35
|
].exclude?(e.class.to_s)
|
|
35
36
|
end
|
|
36
37
|
|
|
@@ -38,6 +39,11 @@ module RailsAdmin
|
|
|
38
39
|
model.scoped
|
|
39
40
|
end
|
|
40
41
|
|
|
42
|
+
# Criteria#none is lost when merged into another criteria
|
|
43
|
+
def none
|
|
44
|
+
scoped.in(_id: [])
|
|
45
|
+
end
|
|
46
|
+
|
|
41
47
|
def first(options = {}, scope = nil)
|
|
42
48
|
all(options, scope).first
|
|
43
49
|
end
|
|
@@ -152,7 +158,7 @@ module RailsAdmin
|
|
|
152
158
|
statements = []
|
|
153
159
|
|
|
154
160
|
filters.each_pair do |field_name, filters_dump|
|
|
155
|
-
filters_dump.
|
|
161
|
+
filters_dump.each_value do |filter_dump|
|
|
156
162
|
field = fields.detect { |f| f.name.to_s == field_name }
|
|
157
163
|
next unless field
|
|
158
164
|
|
|
@@ -250,8 +256,12 @@ module RailsAdmin
|
|
|
250
256
|
end
|
|
251
257
|
|
|
252
258
|
def build_statement_for_boolean
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
case @value
|
|
260
|
+
when 'false', 'f', '0'
|
|
261
|
+
{@column => false}
|
|
262
|
+
when 'true', 't', '1'
|
|
263
|
+
{@column => true}
|
|
264
|
+
end
|
|
255
265
|
end
|
|
256
266
|
|
|
257
267
|
def column_for_value(value)
|
|
@@ -19,7 +19,8 @@ module RailsAdmin
|
|
|
19
19
|
format = params[:json] && :json || params[:csv] && :csv || params[:xml] && :xml
|
|
20
20
|
if format
|
|
21
21
|
request.format = format
|
|
22
|
-
|
|
22
|
+
serialization_schema # built while @action is still export
|
|
23
|
+
@schema = serialization_schema.sanitize(params[:schema].slice(:include, :methods, :only).permit!.to_h) if params[:schema]
|
|
23
24
|
@objects = list_entries(@model_config, :export)
|
|
24
25
|
index
|
|
25
26
|
else
|
|
@@ -50,11 +50,13 @@ module RailsAdmin
|
|
|
50
50
|
format.json do
|
|
51
51
|
output =
|
|
52
52
|
if params[:compact]
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
if @association
|
|
54
|
+
@association.collection(@objects).collect { |(label, id)| {id: id, label: label} }
|
|
55
|
+
else
|
|
56
|
+
@objects.collect { |object| {id: object.id.to_s, label: object.send(@model_config.object_label_method).to_s} }
|
|
57
|
+
end
|
|
56
58
|
else
|
|
57
|
-
@objects.to_json(@schema)
|
|
59
|
+
@objects.to_json(@schema || serialization_schema.default)
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
if params[:send_data]
|
|
@@ -65,7 +67,7 @@ module RailsAdmin
|
|
|
65
67
|
end
|
|
66
68
|
|
|
67
69
|
format.xml do
|
|
68
|
-
output = @objects.to_xml(@schema)
|
|
70
|
+
output = @objects.to_xml(@schema || serialization_schema.default)
|
|
69
71
|
if params[:send_data]
|
|
70
72
|
send_data output, filename: "#{params[:model_name]}_#{DateTime.now.strftime('%Y-%m-%d_%Hh%Mm%S')}.xml"
|
|
71
73
|
else
|
|
@@ -21,7 +21,7 @@ module RailsAdmin
|
|
|
21
21
|
register_instance_option :controller do
|
|
22
22
|
proc do
|
|
23
23
|
respond_to do |format|
|
|
24
|
-
format.json { render json: @object }
|
|
24
|
+
format.json { render json: @object.to_json(serialization_schema.default) }
|
|
25
25
|
format.html { render @action.template_name }
|
|
26
26
|
end
|
|
27
27
|
end
|
|
@@ -9,7 +9,7 @@ module RailsAdmin
|
|
|
9
9
|
base.send :extend, ClassMethods
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def has_option?(name) # rubocop:disable Naming/
|
|
12
|
+
def has_option?(name) # rubocop:disable Naming/PredicatePrefix
|
|
13
13
|
options = self.class.instance_variable_get('@config_options')
|
|
14
14
|
options&.key?(name)
|
|
15
15
|
end
|
|
@@ -13,7 +13,7 @@ module RailsAdmin
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def method_name
|
|
16
|
-
association.key_accessor
|
|
16
|
+
nested_form ? :"#{name}_attributes" : association.key_accessor
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
register_instance_option :pretty_value do
|
|
@@ -56,7 +56,30 @@ module RailsAdmin
|
|
|
56
56
|
# preload entire associated collection (per associated_collection_scope) on load
|
|
57
57
|
# Be sure to set limit in associated_collection_scope if set is large
|
|
58
58
|
register_instance_option :associated_collection_cache_all do
|
|
59
|
-
@associated_collection_cache_all ||= (associated_model_config.abstract_model.count < associated_model_limit)
|
|
59
|
+
@associated_collection_cache_all ||= dynamically_scope_by.blank? && (associated_model_config.abstract_model.count < associated_model_limit)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# client-side dynamic scoping
|
|
63
|
+
register_instance_option :dynamically_scope_by do
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# parses #dynamically_scope_by and returns a Hash in the form of
|
|
68
|
+
# {[form field name in this model]: [field name in the associated model]}
|
|
69
|
+
def dynamic_scope_relationships
|
|
70
|
+
@dynamic_scope_relationships ||=
|
|
71
|
+
Array.wrap(dynamically_scope_by).flat_map do |field|
|
|
72
|
+
field.is_a?(Hash) ? field.to_a : [[field, field]]
|
|
73
|
+
end.map do |field_name, target_name| # rubocop:disable Style/MultilineBlockChain
|
|
74
|
+
field = section.fields.detect { |f| f.name == field_name }
|
|
75
|
+
raise "Field '#{field_name}' was given for #dynamically_scope_by but not found in '#{abstract_model.model_name}'" unless field
|
|
76
|
+
|
|
77
|
+
target_field = associated_model_config.list.fields.detect { |f| f.name == target_name }
|
|
78
|
+
raise "Field '#{field_name}' was given for #dynamically_scope_by but not found in '#{associated_model_config.abstract_model.model_name}'" unless target_field
|
|
79
|
+
raise "Field '#{field_name}' in '#{associated_model_config.abstract_model.model_name}' can't be used for dynamic scoping because it's not filterable" unless target_field.filterable
|
|
80
|
+
|
|
81
|
+
[field.method_name, target_name]
|
|
82
|
+
end.to_h
|
|
60
83
|
end
|
|
61
84
|
|
|
62
85
|
# determines whether association's elements can be removed
|
|
@@ -111,6 +134,12 @@ module RailsAdmin
|
|
|
111
134
|
bindings[:object].send(association.name)
|
|
112
135
|
end
|
|
113
136
|
|
|
137
|
+
# Returns collection of all selectable records
|
|
138
|
+
def collection(scope = nil)
|
|
139
|
+
(scope || bindings[:controller].list_entries(associated_model_config, :index, associated_collection_scope, false)).
|
|
140
|
+
map { |o| [o.send(associated_object_label_method), format_key(o.send(associated_primary_key)).to_s] }
|
|
141
|
+
end
|
|
142
|
+
|
|
114
143
|
# has many?
|
|
115
144
|
def multiple?
|
|
116
145
|
true
|
|
@@ -123,6 +152,16 @@ module RailsAdmin
|
|
|
123
152
|
def associated_model_limit
|
|
124
153
|
RailsAdmin.config.default_associated_collection_limit
|
|
125
154
|
end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def format_key(key)
|
|
159
|
+
if key.is_a?(Array)
|
|
160
|
+
RailsAdmin.config.composite_keys_serializer.serialize(key)
|
|
161
|
+
else
|
|
162
|
+
key
|
|
163
|
+
end
|
|
164
|
+
end
|
|
126
165
|
end
|
|
127
166
|
end
|
|
128
167
|
end
|
|
@@ -62,15 +62,15 @@ module RailsAdmin
|
|
|
62
62
|
|
|
63
63
|
def sort_column
|
|
64
64
|
if sortable == true
|
|
65
|
-
"#{abstract_model.
|
|
65
|
+
"#{abstract_model.quoted_table_name}.#{abstract_model.quote_column_name(name)}"
|
|
66
66
|
elsif (sortable.is_a?(String) || sortable.is_a?(Symbol)) && sortable.to_s.include?('.') # just provide sortable, don't do anything smart
|
|
67
67
|
sortable
|
|
68
68
|
elsif sortable.is_a?(Hash) # just join sortable hash, don't do anything smart
|
|
69
69
|
"#{sortable.keys.first}.#{sortable.values.first}"
|
|
70
|
-
elsif association # use column on target table
|
|
71
|
-
"#{associated_model_config.abstract_model.
|
|
70
|
+
elsif association? # use column on target table
|
|
71
|
+
"#{associated_model_config.abstract_model.quoted_table_name}.#{abstract_model.quote_column_name(sortable)}"
|
|
72
72
|
else # use described column in the field conf.
|
|
73
|
-
"#{abstract_model.
|
|
73
|
+
"#{abstract_model.quoted_table_name}.#{abstract_model.quote_column_name(sortable)}"
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
|
|
@@ -357,7 +357,7 @@ module RailsAdmin
|
|
|
357
357
|
|
|
358
358
|
def generic_field_help
|
|
359
359
|
model = abstract_model.model_name.underscore
|
|
360
|
-
model_lookup = "admin.help.#{model}.#{name}"
|
|
360
|
+
model_lookup = :"admin.help.#{model}.#{name}"
|
|
361
361
|
translated = I18n.translate(model_lookup, help: generic_help, default: [generic_help])
|
|
362
362
|
(translated.is_a?(Hash) ? translated.to_a.first[1] : translated).html_safe
|
|
363
363
|
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails_admin/config/fields/association'
|
|
4
|
+
|
|
5
|
+
module RailsAdmin
|
|
6
|
+
module Config
|
|
7
|
+
module Fields
|
|
8
|
+
class CollectionAssociation < Association
|
|
9
|
+
# orderable associated objects
|
|
10
|
+
register_instance_option :orderable do
|
|
11
|
+
false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
register_instance_option :partial do
|
|
15
|
+
nested_form ? :form_nested_many : :form_filtering_multiselect
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def collection(scope = nil)
|
|
19
|
+
if scope
|
|
20
|
+
super
|
|
21
|
+
elsif associated_collection_cache_all
|
|
22
|
+
selected = selected_ids
|
|
23
|
+
i = 0
|
|
24
|
+
super.sort_by { |a| [selected.index(a[1]) || selected.size, i += 1] }
|
|
25
|
+
else
|
|
26
|
+
value.map { |o| [o.send(associated_object_label_method), format_key(o.send(associated_primary_key))] }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def associated_prepopulate_params
|
|
31
|
+
{associated_model_config.abstract_model.param_key => {association.foreign_key => bindings[:object].try(:id)}}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def multiple?
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def selected_ids
|
|
39
|
+
value.map { |s| format_key(s.send(associated_primary_key)).to_s }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def parse_input(params)
|
|
43
|
+
return unless associated_model_config.abstract_model.primary_key.is_a?(Array)
|
|
44
|
+
|
|
45
|
+
if nested_form
|
|
46
|
+
params[method_name].each_value do |value|
|
|
47
|
+
value[:id] = associated_model_config.abstract_model.parse_id(value[:id])
|
|
48
|
+
end
|
|
49
|
+
elsif params[method_name].is_a?(Array)
|
|
50
|
+
params[method_name] = params[method_name].map { |key| associated_model_config.abstract_model.parse_id(key) if key.present? }.compact
|
|
51
|
+
if params[method_name].empty?
|
|
52
|
+
# Workaround for Arel::Visitors::UnsupportedVisitError in #ids_writer, until https://github.com/rails/rails/pull/51116 is in place
|
|
53
|
+
params.delete(method_name)
|
|
54
|
+
params[name] = []
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def form_default_value
|
|
60
|
+
(default_value if bindings[:object].new_record? && value.empty?)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def form_value
|
|
64
|
+
form_default_value.nil? ? selected_ids : form_default_value
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def widget_options
|
|
68
|
+
{
|
|
69
|
+
xhr: !associated_collection_cache_all,
|
|
70
|
+
'edit-url': (inline_edit && bindings[:view].authorized?(:edit, associated_model_config.abstract_model) ? bindings[:view].edit_path(model_name: associated_model_config.abstract_model.to_param, id: '__ID__') : ''),
|
|
71
|
+
remote_source: bindings[:view].index_path(associated_model_config.abstract_model, source_object_id: abstract_model.format_id(bindings[:object].id), source_abstract_model: abstract_model.to_param, associated_collection: name, current_action: bindings[:view].current_action, compact: true),
|
|
72
|
+
scopeBy: dynamic_scope_relationships,
|
|
73
|
+
sortable: !!orderable,
|
|
74
|
+
removable: !!removable,
|
|
75
|
+
cacheAll: !!associated_collection_cache_all,
|
|
76
|
+
regional: {
|
|
77
|
+
add: ::I18n.t('admin.misc.add_new'),
|
|
78
|
+
chooseAll: ::I18n.t('admin.misc.chose_all'),
|
|
79
|
+
clearAll: ::I18n.t('admin.misc.clear_all'),
|
|
80
|
+
down: ::I18n.t('admin.misc.down'),
|
|
81
|
+
remove: ::I18n.t('admin.misc.remove'),
|
|
82
|
+
search: ::I18n.t('admin.misc.search'),
|
|
83
|
+
up: ::I18n.t('admin.misc.up'),
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -13,9 +13,9 @@ RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
|
|
|
13
13
|
fields << field
|
|
14
14
|
associations =
|
|
15
15
|
if properties.type == :has_many
|
|
16
|
-
["#{name}_attachments"
|
|
16
|
+
[:"#{name}_attachments", :"#{name}_blobs"]
|
|
17
17
|
else
|
|
18
|
-
["#{name}_attachment"
|
|
18
|
+
[:"#{name}_attachment", :"#{name}_blob"]
|
|
19
19
|
end
|
|
20
20
|
children_fields = associations.map do |child_name|
|
|
21
21
|
child_association = parent.abstract_model.associations.detect { |p| p.name.to_sym == child_name }
|
|
@@ -7,7 +7,7 @@ require 'rails_admin/config/fields/types/file_upload'
|
|
|
7
7
|
RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
|
|
8
8
|
model = parent.abstract_model.model
|
|
9
9
|
if defined?(::CarrierWave) && model.is_a?(CarrierWave::Mount) && model.uploaders.include?(attachment_name = properties.name.to_s.chomp('_file_name').to_sym)
|
|
10
|
-
columns = [model.uploader_options[attachment_name][:mount_on] || attachment_name, "#{attachment_name}_content_type"
|
|
10
|
+
columns = [model.uploader_options[attachment_name][:mount_on] || attachment_name, :"#{attachment_name}_content_type", :"#{attachment_name}_file_size"]
|
|
11
11
|
field = RailsAdmin::Config::Fields::Types.load(
|
|
12
12
|
%i[serialized json].include?(properties.type) ? :multiple_carrierwave : :carrierwave,
|
|
13
13
|
).new(parent, attachment_name, properties)
|
|
@@ -10,7 +10,7 @@ RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
|
|
|
10
10
|
field = RailsAdmin::Config::Fields::Types.load(:dragonfly).new(parent, attachment_name, properties)
|
|
11
11
|
children_fields = []
|
|
12
12
|
extensions.each do |ext|
|
|
13
|
-
children_column_name = "#{attachment_name}_#{ext}"
|
|
13
|
+
children_column_name = :"#{attachment_name}_#{ext}"
|
|
14
14
|
child_properties = parent.abstract_model.properties.detect { |p| p.name.to_s == children_column_name.to_s }
|
|
15
15
|
next unless child_properties
|
|
16
16
|
|
|
@@ -11,7 +11,7 @@ RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
|
|
|
11
11
|
field = RailsAdmin::Config::Fields::Types.load(:paperclip).new(parent, attachment_name, properties)
|
|
12
12
|
children_fields = []
|
|
13
13
|
extensions.each do |ext|
|
|
14
|
-
children_column_name = "#{attachment_name}_#{ext}"
|
|
14
|
+
children_column_name = :"#{attachment_name}_#{ext}"
|
|
15
15
|
child_properties = parent.abstract_model.properties.detect { |p| p.name.to_s == children_column_name.to_s }
|
|
16
16
|
next unless child_properties
|
|
17
17
|
|
|
@@ -16,7 +16,7 @@ RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
|
|
|
16
16
|
field = RailsAdmin::Config::Fields::Types.load(:shrine).new(parent, attachment_name, properties)
|
|
17
17
|
fields << field
|
|
18
18
|
|
|
19
|
-
data_field_name = "#{attachment_name}_data"
|
|
19
|
+
data_field_name = :"#{attachment_name}_data"
|
|
20
20
|
child_properties = parent.abstract_model.properties.detect { |p| p.name == data_field_name }
|
|
21
21
|
next true unless child_properties
|
|
22
22
|
|