rails_admin 3.1.4 → 3.2.0.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +19 -14
  3. data/README.md +2 -2
  4. data/app/assets/javascripts/rails_admin/application.js.erb +3 -2
  5. data/app/assets/stylesheets/rails_admin/application.scss.erb +1 -1
  6. data/app/controllers/rails_admin/main_controller.rb +5 -1
  7. data/app/helpers/rails_admin/application_helper.rb +4 -0
  8. data/app/helpers/rails_admin/form_builder.rb +2 -2
  9. data/app/helpers/rails_admin/main_helper.rb +1 -1
  10. data/app/views/layouts/rails_admin/_head.html.erb +7 -5
  11. data/app/views/rails_admin/main/_form_boolean.html.erb +2 -2
  12. data/app/views/rails_admin/main/_form_filtering_multiselect.html.erb +5 -35
  13. data/app/views/rails_admin/main/_form_filtering_select.html.erb +6 -18
  14. data/app/views/rails_admin/main/_form_nested_many.html.erb +1 -1
  15. data/app/views/rails_admin/main/_form_nested_one.html.erb +1 -1
  16. data/app/views/rails_admin/main/_form_polymorphic_association.html.erb +12 -21
  17. data/app/views/rails_admin/main/delete.html.erb +1 -1
  18. data/config/initializers/active_record_extensions.rb +0 -23
  19. data/lib/generators/rails_admin/importmap_formatter.rb +1 -1
  20. data/lib/generators/rails_admin/install_generator.rb +13 -1
  21. data/lib/generators/rails_admin/templates/rails_admin.vite.js +2 -0
  22. data/lib/rails_admin/abstract_model.rb +18 -7
  23. data/lib/rails_admin/adapters/active_record/association.rb +25 -8
  24. data/lib/rails_admin/adapters/active_record/object_extension.rb +0 -18
  25. data/lib/rails_admin/adapters/active_record.rb +51 -5
  26. data/lib/rails_admin/adapters/mongoid/association.rb +1 -1
  27. data/lib/rails_admin/adapters/mongoid/object_extension.rb +0 -5
  28. data/lib/rails_admin/adapters/mongoid.rb +6 -3
  29. data/lib/rails_admin/config/actions/index.rb +5 -3
  30. data/lib/rails_admin/config/fields/association.rb +41 -2
  31. data/lib/rails_admin/config/fields/base.rb +4 -4
  32. data/lib/rails_admin/config/fields/collection_association.rb +90 -0
  33. data/lib/rails_admin/config/fields/singular_association.rb +59 -0
  34. data/lib/rails_admin/config/fields/types/active_storage.rb +12 -7
  35. data/lib/rails_admin/config/fields/types/all.rb +0 -1
  36. data/lib/rails_admin/config/fields/types/belongs_to_association.rb +17 -20
  37. data/lib/rails_admin/config/fields/types/dragonfly.rb +0 -1
  38. data/lib/rails_admin/config/fields/types/file_upload.rb +7 -1
  39. data/lib/rails_admin/config/fields/types/has_and_belongs_to_many_association.rb +2 -2
  40. data/lib/rails_admin/config/fields/types/has_many_association.rb +2 -24
  41. data/lib/rails_admin/config/fields/types/has_one_association.rb +12 -22
  42. data/lib/rails_admin/config/fields/types/multiple_active_storage.rb +13 -8
  43. data/lib/rails_admin/config/fields/types/multiple_file_upload.rb +7 -1
  44. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +32 -9
  45. data/lib/rails_admin/config.rb +5 -0
  46. data/lib/rails_admin/engine.rb +5 -0
  47. data/lib/rails_admin/extensions/url_for_extension.rb +15 -0
  48. data/lib/rails_admin/support/composite_keys_serializer.rb +15 -0
  49. data/lib/rails_admin/support/datetime.rb +1 -0
  50. data/lib/rails_admin/version.rb +3 -3
  51. data/package.json +2 -2
  52. data/src/rails_admin/abstract-select.js +30 -0
  53. data/src/rails_admin/base.js +4 -1
  54. data/src/rails_admin/filtering-multiselect.js +2 -4
  55. data/src/rails_admin/filtering-select.js +1 -4
  56. data/src/rails_admin/widgets.js +1 -0
  57. metadata +39 -15
  58. data/lib/rails_admin/adapters/composite_primary_keys/association.rb +0 -45
  59. data/lib/rails_admin/adapters/composite_primary_keys.rb +0 -40
  60. data/lib/rails_admin/config/fields/types/composite_keys_belongs_to_association.rb +0 -31
@@ -15,7 +15,7 @@ module RailsAdmin
15
15
  end
16
16
 
17
17
  def get(id, scope = scoped)
18
- object = scope.where(primary_key => id).first
18
+ object = primary_key_scope(scope, id).first
19
19
  return unless object
20
20
 
21
21
  object.extend(ObjectExtension)
@@ -72,6 +72,14 @@ module RailsAdmin
72
72
 
73
73
  delegate :primary_key, :table_name, to: :model, prefix: false
74
74
 
75
+ def quoted_table_name
76
+ model.quoted_table_name
77
+ end
78
+
79
+ def quote_column_name(name)
80
+ model.connection.quote_column_name(name)
81
+ end
82
+
75
83
  def encoding
76
84
  adapter =
77
85
  if ::ActiveRecord::Base.respond_to?(:connection_db_config)
@@ -107,10 +115,42 @@ module RailsAdmin
107
115
  true
108
116
  end
109
117
 
118
+ def format_id(id)
119
+ if primary_key.is_a? Array
120
+ RailsAdmin.config.composite_keys_serializer.serialize(id)
121
+ else
122
+ id
123
+ end
124
+ end
125
+
126
+ def parse_id(id)
127
+ if primary_key.is_a?(Array)
128
+ ids = RailsAdmin.config.composite_keys_serializer.deserialize(id)
129
+ primary_key.each_with_index do |key, i|
130
+ ids[i] = model.type_for_attribute(key).cast(ids[i])
131
+ end
132
+ ids
133
+ else
134
+ id
135
+ end
136
+ end
137
+
110
138
  private
111
139
 
140
+ def primary_key_scope(scope, id)
141
+ if primary_key.is_a? Array
142
+ scope.where(primary_key.zip(parse_id(id)).to_h)
143
+ else
144
+ scope.where(primary_key => id)
145
+ end
146
+ end
147
+
112
148
  def bulk_scope(scope, options)
113
- scope.where(primary_key => options[:bulk_ids])
149
+ if primary_key.is_a? Array
150
+ options[:bulk_ids].map { |id| primary_key_scope(scope, id) }.reduce(&:or)
151
+ else
152
+ scope.where(primary_key => options[:bulk_ids])
153
+ end
114
154
  end
115
155
 
116
156
  def sort_scope(scope, options)
@@ -201,6 +241,8 @@ module RailsAdmin
201
241
  case @type
202
242
  when :boolean
203
243
  boolean_unary_operators
244
+ when :uuid
245
+ uuid_unary_operators
204
246
  when :integer, :decimal, :float
205
247
  numeric_unary_operators
206
248
  else
@@ -230,6 +272,7 @@ module RailsAdmin
230
272
  )
231
273
  end
232
274
  alias_method :numeric_unary_operators, :boolean_unary_operators
275
+ alias_method :uuid_unary_operators, :boolean_unary_operators
233
276
 
234
277
  def range_filter(min, max)
235
278
  if min && max && min == max
@@ -255,9 +298,12 @@ module RailsAdmin
255
298
  end
256
299
 
257
300
  def build_statement_for_boolean
258
- return ["(#{@column} IS NULL OR #{@column} = ?)", false] if %w[false f 0].include?(@value)
259
-
260
- ["(#{@column} = ?)", true] if %w[true t 1].include?(@value)
301
+ case @value
302
+ when 'false', 'f', '0'
303
+ ["(#{@column} IS NULL OR #{@column} = ?)", false]
304
+ when 'true', 't', '1'
305
+ ["(#{@column} = ?)", true]
306
+ end
261
307
  end
262
308
 
263
309
  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, model.name, name) || []
49
+ polymorphic_parents(:mongoid, association.inverse_class_name, name) || []
50
50
  else
51
51
  association.klass
52
52
  end
@@ -20,11 +20,6 @@ module RailsAdmin
20
20
  send(name)&.save
21
21
  end
22
22
  end
23
- object.instance_eval <<-RUBY, __FILE__, __LINE__ + 1
24
- def #{name}_id=(item_id)
25
- self.#{name} = (#{association.klass}.find(item_id) rescue nil)
26
- end
27
- RUBY
28
23
  end
29
24
  end
30
25
  end
@@ -251,9 +251,12 @@ module RailsAdmin
251
251
  end
252
252
 
253
253
  def build_statement_for_boolean
254
- return {@column => false} if %w[false f 0].include?(@value)
255
-
256
- {@column => true} if %w[true t 1].include?(@value)
254
+ case @value
255
+ when 'false', 'f', '0'
256
+ {@column => false}
257
+ when 'true', 't', '1'
258
+ {@column => true}
259
+ end
257
260
  end
258
261
 
259
262
  def column_for_value(value)
@@ -50,9 +50,11 @@ module RailsAdmin
50
50
  format.json do
51
51
  output =
52
52
  if params[:compact]
53
- primary_key_method = @association ? @association.associated_primary_key : @model_config.abstract_model.primary_key
54
- label_method = @model_config.object_label_method
55
- @objects.collect { |o| {id: o.send(primary_key_method).to_s, label: o.send(label_method).to_s} }
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
59
  @objects.to_json(@schema)
58
60
  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.table_name}.#{name}"
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.table_name}.#{sortable}"
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.table_name}.#{sortable}"
73
+ "#{abstract_model.quoted_table_name}.#{abstract_model.quote_column_name(sortable)}"
74
74
  end
75
75
  end
76
76
 
@@ -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
@@ -0,0 +1,59 @@
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 SingularAssociation < Association
9
+ register_instance_option :filter_operators do
10
+ %w[_discard like not_like is starts_with ends_with] + (required? ? [] : %w[_separator _present _blank])
11
+ end
12
+
13
+ register_instance_option :formatted_value do
14
+ (o = value) && o.send(associated_model_config.object_label_method)
15
+ end
16
+
17
+ register_instance_option :partial do
18
+ nested_form ? :form_nested_one : :form_filtering_select
19
+ end
20
+
21
+ def collection(scope = nil)
22
+ if associated_collection_cache_all || scope
23
+ super
24
+ else
25
+ [[formatted_value, selected_id]]
26
+ end
27
+ end
28
+
29
+ def multiple?
30
+ false
31
+ end
32
+
33
+ def selected_id
34
+ raise NoMethodError # abstract
35
+ end
36
+
37
+ def parse_input(params)
38
+ return unless nested_form && params[method_name].try(:[], :id).present?
39
+
40
+ ids = associated_model_config.abstract_model.parse_id(params[method_name][:id])
41
+ ids = ids.to_composite_keys.to_s if ids.respond_to?(:to_composite_keys)
42
+ params[method_name][:id] = ids
43
+ end
44
+
45
+ def form_value
46
+ form_default_value.nil? ? selected_id : form_default_value
47
+ end
48
+
49
+ def widget_options
50
+ {
51
+ xhr: !associated_collection_cache_all,
52
+ 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),
53
+ scopeBy: dynamic_scope_relationships,
54
+ }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -18,10 +18,7 @@ module RailsAdmin
18
18
  end
19
19
 
20
20
  register_instance_option :image? do
21
- if value
22
- mime_type = Mime::Type.lookup_by_extension(value.filename.extension_without_delimiter)
23
- mime_type.to_s.match?(/^image/)
24
- end
21
+ value && (value.representable? || value.content_type.match?(/^image/))
25
22
  end
26
23
 
27
24
  register_instance_option :eager_load do
@@ -40,14 +37,22 @@ module RailsAdmin
40
37
  )
41
38
  end
42
39
 
40
+ register_instance_option :searchable do
41
+ false
42
+ end
43
+
44
+ register_instance_option :sortable do
45
+ false
46
+ end
47
+
43
48
  def resource_url(thumb = false)
44
49
  return nil unless value
45
50
 
46
- if thumb && value.variable?
51
+ if thumb && value.representable?
47
52
  thumb = thumb_method if thumb == true
48
- variant = value.variant(thumb)
53
+ representation = value.representation(thumb)
49
54
  Rails.application.routes.url_helpers.rails_blob_representation_path(
50
- variant.blob.signed_id, variant.variation.key, variant.blob.filename, only_path: true
55
+ representation.blob.signed_id, representation.variation.key, representation.blob.filename, only_path: true
51
56
  )
52
57
  else
53
58
  Rails.application.routes.url_helpers.rails_blob_path(value, only_path: true)
@@ -6,7 +6,6 @@ require 'rails_admin/config/fields/types/active_storage'
6
6
  require 'rails_admin/config/fields/types/belongs_to_association'
7
7
  require 'rails_admin/config/fields/types/boolean'
8
8
  require 'rails_admin/config/fields/types/bson_object_id'
9
- require 'rails_admin/config/fields/types/composite_keys_belongs_to_association'
10
9
  require 'rails_admin/config/fields/types/date'
11
10
  require 'rails_admin/config/fields/types/datetime'
12
11
  require 'rails_admin/config/fields/types/decimal'
@@ -1,22 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails_admin/config/fields/association'
3
+ require 'rails_admin/config/fields/singular_association'
4
4
 
5
5
  module RailsAdmin
6
6
  module Config
7
7
  module Fields
8
8
  module Types
9
- class BelongsToAssociation < RailsAdmin::Config::Fields::Association
9
+ class BelongsToAssociation < RailsAdmin::Config::Fields::SingularAssociation
10
10
  RailsAdmin::Config::Fields::Types.register(self)
11
11
 
12
- register_instance_option :filter_operators do
13
- %w[_discard like not_like is starts_with ends_with] + (required? ? [] : %w[_separator _present _blank])
14
- end
15
-
16
- register_instance_option :formatted_value do
17
- (o = value) && o.send(associated_model_config.object_label_method)
18
- end
19
-
20
12
  register_instance_option :sortable do
21
13
  @sortable ||= abstract_model.adapter_supports_joins? && associated_model_config.abstract_model.properties.collect(&:name).include?(associated_model_config.object_label_method) ? associated_model_config.object_label_method : {abstract_model.table_name => method_name}
22
14
  end
@@ -25,24 +17,29 @@ module RailsAdmin
25
17
  @searchable ||= associated_model_config.abstract_model.properties.collect(&:name).include?(associated_model_config.object_label_method) ? [associated_model_config.object_label_method, {abstract_model.model => method_name}] : {abstract_model.model => method_name}
26
18
  end
27
19
 
28
- register_instance_option :partial do
29
- nested_form ? :form_nested_one : :form_filtering_select
30
- end
31
-
32
20
  register_instance_option :eager_load do
33
21
  true
34
22
  end
35
23
 
36
- def selected_id
37
- bindings[:object].safe_send(association.key_accessor)
24
+ register_instance_option :allowed_methods do
25
+ nested_form ? [method_name] : Array(association.foreign_key)
38
26
  end
39
27
 
40
- def method_name
41
- nested_form ? :"#{name}_attributes" : super
28
+ def selected_id
29
+ if association.foreign_key.is_a?(Array)
30
+ format_key(association.foreign_key.map { |attribute| bindings[:object].safe_send(attribute) })
31
+ else
32
+ bindings[:object].safe_send(association.key_accessor)
33
+ end
42
34
  end
43
35
 
44
- def multiple?
45
- false
36
+ def parse_input(params)
37
+ return super if nested_form
38
+ return unless params[method_name].present? && association.foreign_key.is_a?(Array)
39
+
40
+ association.foreign_key.zip(RailsAdmin.config.composite_keys_serializer.deserialize(params.delete(method_name))).each do |key, value|
41
+ params[key] = value
42
+ end
46
43
  end
47
44
  end
48
45
  end
@@ -12,7 +12,6 @@ module RailsAdmin
12
12
  RailsAdmin::Config::Fields::Types.register(self)
13
13
 
14
14
  register_instance_option :image? do
15
- false unless value
16
15
  if abstract_model.model.new.respond_to?("#{name}_name")
17
16
  mime_type = Mime::Type.lookup_by_extension(bindings[:object].send("#{name}_name").to_s.split('.').last)
18
17
  mime_type.to_s.match?(/^image/)
@@ -52,7 +52,7 @@ module RailsAdmin
52
52
  end
53
53
 
54
54
  register_instance_option :image? do
55
- mime_type = Mime::Type.lookup_by_extension(resource_url.to_s.split('.').last)
55
+ mime_type = Mime::Type.lookup_by_extension(extension)
56
56
  mime_type.to_s.match?(/^image/)
57
57
  end
58
58
 
@@ -66,6 +66,12 @@ module RailsAdmin
66
66
  }
67
67
  end
68
68
 
69
+ def extension
70
+ URI.parse(resource_url).path.split('.').last
71
+ rescue URI::InvalidURIError
72
+ nil
73
+ end
74
+
69
75
  # virtual class
70
76
  def resource_url
71
77
  raise 'not implemented'
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails_admin/config/fields/types/has_many_association'
3
+ require 'rails_admin/config/fields/collection_association'
4
4
 
5
5
  module RailsAdmin
6
6
  module Config
7
7
  module Fields
8
8
  module Types
9
- class HasAndBelongsToManyAssociation < RailsAdmin::Config::Fields::Types::HasManyAssociation
9
+ class HasAndBelongsToManyAssociation < RailsAdmin::Config::Fields::CollectionAssociation
10
10
  # Register field type for the type loader
11
11
  RailsAdmin::Config::Fields::Types.register(self)
12
12
  end
@@ -1,36 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails_admin/config/fields/association'
3
+ require 'rails_admin/config/fields/collection_association'
4
4
 
5
5
  module RailsAdmin
6
6
  module Config
7
7
  module Fields
8
8
  module Types
9
- class HasManyAssociation < RailsAdmin::Config::Fields::Association
9
+ class HasManyAssociation < RailsAdmin::Config::Fields::CollectionAssociation
10
10
  # Register field type for the type loader
11
11
  RailsAdmin::Config::Fields::Types.register(self)
12
-
13
- register_instance_option :partial do
14
- nested_form ? :form_nested_many : :form_filtering_multiselect
15
- end
16
-
17
- # orderable associated objects
18
- register_instance_option :orderable do
19
- false
20
- end
21
-
22
- def method_name
23
- nested_form ? :"#{name}_attributes" : super
24
- end
25
-
26
- # Reader for validation errors of the bound object
27
- def errors
28
- bindings[:object].errors[name]
29
- end
30
-
31
- def associated_prepopulate_params
32
- {associated_model_config.abstract_model.param_key => {association.foreign_key => bindings[:object].try(:id)}}
33
- end
34
12
  end
35
13
  end
36
14
  end
@@ -1,42 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails_admin/config/fields/association'
3
+ require 'rails_admin/config/fields/singular_association'
4
4
 
5
5
  module RailsAdmin
6
6
  module Config
7
7
  module Fields
8
8
  module Types
9
- class HasOneAssociation < RailsAdmin::Config::Fields::Association
9
+ class HasOneAssociation < RailsAdmin::Config::Fields::SingularAssociation
10
10
  # Register field type for the type loader
11
11
  RailsAdmin::Config::Fields::Types.register(self)
12
12
 
13
- register_instance_option :filter_operators do
14
- %w[_discard like not_like is starts_with ends_with] + (required? ? [] : %w[_separator _present _blank])
13
+ register_instance_option :allowed_methods do
14
+ nested_form ? [method_name] : [name]
15
15
  end
16
16
 
17
- register_instance_option :partial do
18
- nested_form ? :form_nested_one : :form_filtering_select
19
- end
20
-
21
- # Accessor for field's formatted value
22
- register_instance_option :formatted_value do
23
- (o = value) && o.send(associated_model_config.object_label_method)
24
- end
25
-
26
- def selected_id
27
- value.try(:id).try(:to_s)
17
+ def associated_prepopulate_params
18
+ {associated_model_config.abstract_model.param_key => {association.foreign_key => bindings[:object].try(:id)}}
28
19
  end
29
20
 
30
- def method_name
31
- nested_form ? :"#{name}_attributes" : super
32
- end
21
+ def parse_input(params)
22
+ return super if nested_form
33
23
 
34
- def multiple?
35
- false
24
+ id = params.delete(method_name)
25
+ params[name] = associated_model_config.abstract_model.get(id) if id
36
26
  end
37
27
 
38
- def associated_prepopulate_params
39
- {associated_model_config.abstract_model.param_key => {association.foreign_key => bindings[:object].try(:id)}}
28
+ def selected_id
29
+ format_key(value.try(:id)).try(:to_s)
40
30
  end
41
31
  end
42
32
  end