plutonium 0.18.5 → 0.18.7

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/plutonium.js +1 -1
  3. data/app/assets/plutonium.js.map +2 -2
  4. data/app/assets/plutonium.min.js +1 -1
  5. data/app/assets/plutonium.min.js.map +2 -2
  6. data/app/views/resource/interactive_bulk_action.html.erb +1 -1
  7. data/app/views/resource/interactive_resource_action.html.erb +1 -1
  8. data/lib/generators/pu/eject/layout/layout_generator.rb +1 -2
  9. data/lib/generators/pu/eject/shell/shell_generator.rb +1 -3
  10. data/lib/generators/pu/lib/plutonium_generators/concerns/logger.rb +4 -0
  11. data/lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb +80 -0
  12. data/lib/generators/pu/lib/plutonium_generators/concerns/resource_selector.rb +48 -0
  13. data/lib/generators/pu/lib/plutonium_generators/generator.rb +2 -42
  14. data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +1 -4
  15. data/lib/generators/pu/res/conn/conn_generator.rb +9 -21
  16. data/lib/generators/pu/res/scaffold/scaffold_generator.rb +10 -5
  17. data/lib/plutonium/models/has_cents.rb +4 -2
  18. data/lib/plutonium/resource/controller.rb +3 -3
  19. data/lib/plutonium/resource/controllers/authorizable.rb +1 -1
  20. data/lib/plutonium/resource/controllers/crud_actions.rb +17 -17
  21. data/lib/plutonium/resource/controllers/interactive_actions.rb +3 -3
  22. data/lib/plutonium/resource/controllers/presentable.rb +2 -2
  23. data/lib/plutonium/resource/record/associated_with.rb +83 -0
  24. data/lib/plutonium/resource/record/associations.rb +92 -0
  25. data/lib/plutonium/resource/record/field_names.rb +83 -0
  26. data/lib/plutonium/resource/record/labeling.rb +19 -0
  27. data/lib/plutonium/resource/record/routes.rb +66 -0
  28. data/lib/plutonium/resource/record.rb +6 -258
  29. data/lib/plutonium/ui/breadcrumbs.rb +4 -4
  30. data/lib/plutonium/ui/component/methods.rb +4 -12
  31. data/lib/plutonium/ui/form/base.rb +22 -10
  32. data/lib/plutonium/ui/form/components/secure_association.rb +112 -0
  33. data/lib/plutonium/ui/form/components/secure_polymorphic_association.rb +54 -0
  34. data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +0 -1
  35. data/lib/plutonium/ui/form/theme.rb +12 -1
  36. data/lib/plutonium/ui/page/show.rb +1 -1
  37. data/lib/plutonium/ui/page_header.rb +1 -1
  38. data/lib/plutonium/version.rb +1 -1
  39. data/package-lock.json +2 -2
  40. data/package.json +1 -1
  41. data/src/js/controllers/slim_select_controller.js +3 -1
  42. metadata +11 -4
  43. data/lib/plutonium/ui/form/components/belongs_to.rb +0 -66
  44. data/lib/plutonium/ui/form/components/has_many.rb +0 -66
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/plutonium/resource/associations.rb
4
+ module Plutonium
5
+ module Resource
6
+ module Record
7
+ module Associations
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ def belongs_to(name, scope = nil, **options)
12
+ super
13
+ include_secure_association_methods(:belongs_to, name)
14
+ end
15
+
16
+ def has_one(name, scope = nil, **options)
17
+ super
18
+ include_secure_association_methods(:has_one, name)
19
+ end
20
+
21
+ def has_many(name, scope = nil, **options)
22
+ super
23
+ include_secure_association_methods(:has_many, name)
24
+ end
25
+
26
+ def has_and_belongs_to_many(name, scope = nil, **options)
27
+ super
28
+ include_secure_association_methods(:has_and_belongs_to_many, name)
29
+ end
30
+
31
+ private
32
+
33
+ def include_secure_association_methods(association_type, name)
34
+ mod = Module.new
35
+ mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
36
+ extend ActiveSupport::Concern
37
+
38
+ #{generate_sgid_methods(association_type, name)}
39
+
40
+ define_singleton_method(:to_s) { "Plutonium::Resource::Record::Associations::#{association_type.to_s.camelize}(:#{name})" }
41
+ define_singleton_method(:inspect) { "Plutonium::Resource::Record::Associations::#{association_type.to_s.camelize}(:#{name})" }
42
+ RUBY
43
+ include mod
44
+ end
45
+
46
+ def generate_sgid_methods(association_type, name)
47
+ case association_type
48
+ when :belongs_to, :has_one
49
+ generate_singular_sgid_methods(name)
50
+ when :has_many, :has_and_belongs_to_many
51
+ generate_collection_sgid_methods(name)
52
+ end
53
+ end
54
+
55
+ def generate_singular_sgid_methods(name)
56
+ <<-RUBY
57
+ def #{name}_sgid
58
+ #{name}&.to_signed_global_id
59
+ end
60
+
61
+ def #{name}_sgid=(sgid)
62
+ self.#{name} = GlobalID::Locator.locate_signed(sgid)
63
+ end
64
+ RUBY
65
+ end
66
+
67
+ def generate_collection_sgid_methods(name)
68
+ <<-RUBY
69
+ def #{name.to_s.singularize}_sgids
70
+ #{name}.map(&:to_signed_global_id)
71
+ end
72
+
73
+ def #{name.to_s.singularize}_sgids=(sgids)
74
+ self.#{name} = GlobalID::Locator.locate_many_signed(sgids)
75
+ end
76
+
77
+ def add_#{name.to_s.singularize}_sgid(sgid)
78
+ record = GlobalID::Locator.locate_signed(sgid)
79
+ #{name} << record if record
80
+ end
81
+
82
+ def remove_#{name.to_s.singularize}_sgid(sgid)
83
+ record = GlobalID::Locator.locate_signed(sgid)
84
+ #{name}.delete(record) if record
85
+ end
86
+ RUBY
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/plutonium/resource/associations.rb
4
+ module Plutonium
5
+ module Resource
6
+ module Record
7
+ module FieldNames
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ def resource_field_names
12
+ return @resource_field_names if defined?(@resource_field_names) && !Rails.env.local?
13
+
14
+ @resource_field_names = gather_resource_field_names
15
+ end
16
+
17
+ def belongs_to_association_field_names
18
+ return @belongs_to_association_field_names if defined?(@belongs_to_association_field_names) && !Rails.env.local?
19
+
20
+ @belongs_to_association_field_names = reflect_on_all_associations(:belongs_to).map(&:name)
21
+ end
22
+
23
+ def has_one_association_field_names
24
+ return @has_one_association_field_names if defined?(@has_one_association_field_names) && !Rails.env.local?
25
+
26
+ @has_one_association_field_names = reflect_on_all_associations(:has_one)
27
+ .map { |assoc| (!/_attachment$|_blob$/.match?(assoc.name)) ? assoc.name : nil }
28
+ .compact
29
+ end
30
+
31
+ def has_many_association_field_names
32
+ return @has_many_association_field_names if defined?(@has_many_association_field_names) && !Rails.env.local?
33
+
34
+ @has_many_association_field_names = reflect_on_all_associations(:has_many)
35
+ .map { |assoc| (!/_attachments$|_blobs$/.match?(assoc.name)) ? assoc.name : nil }
36
+ .compact
37
+ end
38
+
39
+ def has_one_attached_field_names
40
+ return @has_one_attached_field_names if defined?(@has_one_attached_field_names) && !Rails.env.local?
41
+
42
+ @has_one_attached_field_names = if respond_to?(:reflect_on_all_attachments)
43
+ reflect_on_all_attachments
44
+ .select { |a| a.macro == :has_one_attached }
45
+ .map(&:name)
46
+ else
47
+ []
48
+ end
49
+ end
50
+
51
+ def has_many_attached_field_names
52
+ return @has_many_attached_field_names if defined?(@has_many_attached_field_names) && !Rails.env.local?
53
+
54
+ @has_many_attached_field_names = if respond_to?(:reflect_on_all_attachments)
55
+ reflect_on_all_attachments
56
+ .select { |a| a.macro == :has_many_attached }
57
+ .map(&:name)
58
+ else
59
+ []
60
+ end
61
+ end
62
+
63
+ def content_column_field_names
64
+ return @content_column_field_names if defined?(@content_column_field_names) && !Rails.env.local?
65
+
66
+ @content_column_field_names = content_columns.map { |col| col.name.to_sym }
67
+ end
68
+
69
+ private
70
+
71
+ def gather_resource_field_names
72
+ belongs_to_association_field_names +
73
+ has_one_attached_field_names +
74
+ has_one_association_field_names +
75
+ has_many_attached_field_names +
76
+ has_many_association_field_names +
77
+ content_column_field_names
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/plutonium/resource/associations.rb
4
+ module Plutonium
5
+ module Resource
6
+ module Record
7
+ module Labeling
8
+ def to_label
9
+ %i[name title].each do |method|
10
+ name = send(method) if respond_to?(method)
11
+ return name if name.present?
12
+ end
13
+
14
+ "#{model_name.human} ##{to_param}"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/plutonium/resource/associations.rb
4
+ module Plutonium
5
+ module Resource
6
+ module Record
7
+ module Routes
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ scope :from_path_param, ->(param) { where(id: param) }
12
+ end
13
+
14
+ class_methods do
15
+ def has_many_association_routes
16
+ return @has_many_association_routes if defined?(@has_many_association_routes) && !Rails.env.local?
17
+
18
+ @has_many_association_routes = reflect_on_all_associations(:has_many).map { |assoc| assoc.klass.model_name.plural }
19
+ end
20
+
21
+ def all_nested_attributes_options
22
+ unless Rails.env.local?
23
+ return @all_nested_attributes_options if defined?(@all_nested_attributes_options)
24
+ end
25
+
26
+ @all_nested_attributes_options = reflect_on_all_associations.map do |association|
27
+ setter_method = "#{association.name}_attributes="
28
+ if method_defined?(setter_method)
29
+ [association.name, nested_attributes_options[association.name].merge(
30
+ macro: association.macro,
31
+ class: association.polymorphic? ? nil : association.klass
32
+ )]
33
+ end
34
+ end.compact.to_h
35
+ end
36
+
37
+ private
38
+
39
+ def path_parameter(param_name)
40
+ param_name = param_name.to_sym
41
+
42
+ scope :from_path_param, ->(param) { where(param_name => param) }
43
+
44
+ define_method :to_param do
45
+ return nil unless persisted?
46
+
47
+ send(param_name)
48
+ end
49
+ end
50
+
51
+ def dynamic_path_parameter(param_name)
52
+ param_name = param_name.to_sym
53
+
54
+ scope :from_path_param, ->(param) { where(id: param.split("-").first) }
55
+
56
+ define_method :to_param do
57
+ return nil unless persisted?
58
+
59
+ "#{id}-#{send(param_name)}".parameterize
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -2,265 +2,13 @@ module Plutonium
2
2
  module Resource
3
3
  module Record
4
4
  extend ActiveSupport::Concern
5
- include Plutonium::Models::HasCents
6
-
7
- included do
8
- scope :from_path_param, ->(param) { where(id: param) }
9
-
10
- scope :associated_with, ->(record) do
11
- named_scope = :"associated_with_#{record.model_name.singular}"
12
- return send(named_scope, record) if respond_to?(named_scope)
13
-
14
- # TODO: add support for polymorphic associations
15
- # TODO: add logging
16
- # TODO: memoize this
17
-
18
- own_association = klass.find_association_from_self_to_record(record)
19
- if own_association
20
- return klass.query_based_on_association(own_association, record)
21
- end
22
-
23
- record_association = klass.find_association_to_self_from_record(record)
24
- if record_association
25
- # TODO: add a warning here about a potentially poor performing query
26
- return where(id: record.public_send(record_association.name))
27
- end
28
-
29
- klass.raise_association_error(record, named_scope)
30
- end
31
- end
32
-
33
- class_methods do
34
- # Returns the resource field names
35
- # @return [Array<Symbol>]
36
- def resource_field_names
37
- return @resource_field_names if defined?(@resource_field_names) && !Rails.env.local?
38
-
39
- @resource_field_names = gather_resource_field_names
40
- end
41
-
42
- # Overrides belongs_to to add support for polymorphic associations
43
- # @param [Symbol] name The name of the association
44
- # @param [Proc] scope The scope for the association
45
- # @param [Hash] options The options for the association
46
- def belongs_to(name, scope = nil, **options)
47
- super
48
-
49
- return unless options[:polymorphic]
50
-
51
- mod = Module.new
52
- mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
53
- extend ActiveSupport::Concern
54
-
55
- def #{name}_sgid
56
- #{name}&.to_signed_global_id
57
- end
58
-
59
- def #{name}_sgid=(sgid)
60
- self.#{name} = GlobalID::Locator.locate_signed(sgid)
61
- end
62
-
63
- define_singleton_method(:to_s) { "Plutonium::Polymorphic::BelongsTo(:#{name})" }
64
- define_singleton_method(:inspect) { "Plutonium::Polymorphic::BelongsTo(:#{name})" }
65
- RUBY
66
- include mod
67
- end
68
-
69
- # Returns the names of belongs_to associations
70
- # @return [Array<Symbol>]
71
- def belongs_to_association_field_names
72
- return @belongs_to_association_field_names if defined?(@belongs_to_association_field_names) && !Rails.env.local?
73
-
74
- @belongs_to_association_field_names = reflect_on_all_associations(:belongs_to).map(&:name)
75
- end
76
-
77
- # Returns the names of has_one associations
78
- # @return [Array<Symbol>]
79
- def has_one_association_field_names
80
- return @has_one_association_field_names if defined?(@has_one_association_field_names) && !Rails.env.local?
81
-
82
- @has_one_association_field_names = reflect_on_all_associations(:has_one)
83
- .map { |assoc| (!/_attachment$|_blob$/.match?(assoc.name)) ? assoc.name : nil }
84
- .compact
85
- end
86
-
87
- # Returns the names of has_many associations
88
- # @return [Array<Symbol>]
89
- def has_many_association_field_names
90
- return @has_many_association_field_names if defined?(@has_many_association_field_names) && !Rails.env.local?
91
-
92
- @has_many_association_field_names = reflect_on_all_associations(:has_many)
93
- .map { |assoc| (!/_attachments$|_blobs$/.match?(assoc.name)) ? assoc.name : nil }
94
- .compact
95
- end
96
-
97
- # Returns the names of has_one attached associations
98
- # @return [Array<Symbol>]
99
- def has_one_attached_field_names
100
- return @has_one_attached_field_names if defined?(@has_one_attached_field_names) && !Rails.env.local?
101
-
102
- @has_one_attached_field_names = if respond_to?(:reflect_on_all_attachments)
103
- reflect_on_all_attachments
104
- .select { |a| a.macro == :has_one_attached }
105
- .map(&:name)
106
- else
107
- []
108
- end
109
- end
110
-
111
- # Returns the names of has_many attached associations
112
- # @return [Array<Symbol>]
113
- def has_many_attached_field_names
114
- return @has_many_attached_field_names if defined?(@has_many_attached_field_names) && !Rails.env.local?
115
5
 
116
- @has_many_attached_field_names = if respond_to?(:reflect_on_all_attachments)
117
- reflect_on_all_attachments
118
- .select { |a| a.macro == :has_many_attached }
119
- .map(&:name)
120
- else
121
- []
122
- end
123
- end
124
-
125
- # Returns the names of content columns
126
- # @return [Array<Symbol>]
127
- def content_column_field_names
128
- return @content_column_field_names if defined?(@content_column_field_names) && !Rails.env.local?
129
-
130
- @content_column_field_names = content_columns.map { |col| col.name.to_sym }
131
- end
132
-
133
- # Returns the routes for has_many associations
134
- # @return [Array<Symbol>]
135
- def has_many_association_routes
136
- return @has_many_association_routes if defined?(@has_many_association_routes) && !Rails.env.local?
137
-
138
- @has_many_association_routes = reflect_on_all_associations(:has_many).map { |assoc| assoc.klass.model_name.plural }
139
- end
140
-
141
- # Returns all nested attributes options
142
- # @return [Hash]
143
- def all_nested_attributes_options
144
- unless Rails.env.local?
145
- return @all_nested_attributes_options if defined?(@all_nested_attributes_options)
146
- end
147
-
148
- @all_nested_attributes_options = reflect_on_all_associations.map do |association|
149
- setter_method = "#{association.name}_attributes="
150
- if method_defined?(setter_method)
151
- [association.name, nested_attributes_options[association.name].merge(
152
- macro: association.macro,
153
- class: association.polymorphic? ? nil : association.klass
154
- )]
155
- end
156
- end.compact.to_h
157
- end
158
-
159
- # Finds the association to the given record
160
- # @param [ActiveRecord::Base] record The record to find the association with
161
- # @return [ActiveRecord::Reflection::AssociationReflection, nil]
162
- def find_association_from_self_to_record(record)
163
- reflect_on_all_associations.find do |assoc|
164
- assoc.klass.name == record.class.name unless assoc.polymorphic?
165
- rescue
166
- assoc.check_validity!
167
- raise
168
- end
169
- end
170
-
171
- # Finds the association to self in the given record
172
- # @param [ActiveRecord::Base] record The record to find the association with
173
- # @return [ActiveRecord::Reflection::AssociationReflection, nil]
174
- def find_association_to_self_from_record(record)
175
- record.class.reflect_on_all_associations.find do |assoc|
176
- assoc.klass.name == name
177
- rescue
178
- assoc.check_validity!
179
- raise
180
- end
181
- end
182
-
183
- # Queries based on the association type
184
- # @param [ActiveRecord::Reflection::AssociationReflection] assoc The association
185
- # @param [ActiveRecord::Base] record The record to query with
186
- # @return [ActiveRecord::Relation]
187
- def query_based_on_association(assoc, record)
188
- case assoc.macro
189
- when :has_one
190
- joins(assoc.name).where(assoc.name => {record.class.primary_key => record.id})
191
- when :belongs_to
192
- where(assoc.name => record)
193
- when :has_many
194
- joins(assoc.name).where(assoc.klass.table_name => record)
195
- else
196
- raise NotImplementedError, "associated_with->##{assoc.macro}"
197
- end
198
- end
199
-
200
- # Raises an error for unresolved associations
201
- # @param [ActiveRecord::Base] record The record with unresolved association
202
- # @param [Symbol] named_scope The named scope
203
- # @raise [RuntimeError]
204
- def raise_association_error(record, named_scope)
205
- raise "Could not resolve the association between '#{name}' and '#{record.class.name}'\n\n" \
206
- "Define\n" \
207
- " 1. the associations between the models\n" \
208
- " 2. a named scope on #{name} e.g.\n\n" \
209
- "scope :#{named_scope}, ->(#{record.model_name.singular}) { do_something_here }"
210
- end
211
-
212
- private
213
-
214
- # Defines a scope and method for path parameters
215
- # @param [Symbol] param_name The name of the parameter
216
- def path_parameter(param_name)
217
- param_name = param_name.to_sym
218
-
219
- scope :from_path_param, ->(param) { where(param_name => param) }
220
-
221
- define_method :to_param do
222
- return nil unless persisted?
223
-
224
- send(param_name)
225
- end
226
- end
227
-
228
- # Defines a scope and method for dynamic path parameters
229
- # @param [Symbol] param_name The name of the parameter
230
- def dynamic_path_parameter(param_name)
231
- param_name = param_name.to_sym
232
-
233
- scope :from_path_param, ->(param) { where(id: param.split("-").first) }
234
-
235
- define_method :to_param do
236
- return nil unless persisted?
237
-
238
- "#{id}-#{send(param_name)}".parameterize
239
- end
240
- end
241
-
242
- # Gathers all resource field names
243
- # @return [Array<Symbol>]
244
- def gather_resource_field_names
245
- belongs_to_association_field_names +
246
- has_one_attached_field_names +
247
- has_one_association_field_names +
248
- has_many_attached_field_names +
249
- has_many_association_field_names +
250
- content_column_field_names
251
- end
252
- end
253
-
254
- # Returns a label for the record
255
- # @return [String]
256
- def to_label
257
- %i[name title].each do |method|
258
- name = send(method) if respond_to?(method)
259
- return name if name.present?
260
- end
261
-
262
- "#{model_name.human} ##{to_param}"
263
- end
6
+ include Plutonium::Models::HasCents
7
+ include Plutonium::Resource::Record::Routes
8
+ include Plutonium::Resource::Record::Labeling
9
+ include Plutonium::Resource::Record::FieldNames
10
+ include Plutonium::Resource::Record::Associations
11
+ include Plutonium::Resource::Record::AssociatedWith
264
12
  end
265
13
  end
266
14
  end
@@ -87,7 +87,7 @@ module Plutonium
87
87
  end
88
88
 
89
89
  # Record
90
- if resource_record.present?
90
+ if resource_record?
91
91
  # Record Resource
92
92
  li(class: "flex items-center") do
93
93
  svg(
@@ -112,7 +112,7 @@ module Plutonium
112
112
  end
113
113
 
114
114
  # Record Itself
115
- if resource_record.persisted? && action_name != "show"
115
+ if resource_record!.persisted? && action_name != "show"
116
116
  li(class: "flex items-center") do
117
117
  svg(
118
118
  class: "rtl:rotate-180 block w-3 h-3 mx-1 text-gray-400",
@@ -129,8 +129,8 @@ module Plutonium
129
129
  d: "m1 9 4-4-4-4"
130
130
  )
131
131
  end
132
- link_to display_name_of(resource_record),
133
- resource_url_for(resource_record),
132
+ link_to display_name_of(resource_record!),
133
+ resource_url_for(resource_record!),
134
134
  class:
135
135
  "ms-1 text-sm font-medium text-gray-700 hover:text-primary-600 md:ms-2 dark:text-gray-200 dark:hover:text-white"
136
136
  end
@@ -10,18 +10,6 @@ module Plutonium
10
10
 
11
11
  private
12
12
 
13
- def resource_class
14
- helpers.controller.send(:resource_class)
15
- end
16
-
17
- def resource_record
18
- helpers.controller.send(:resource_record)
19
- end
20
-
21
- def current_parent
22
- helpers.controller.send(:current_parent)
23
- end
24
-
25
13
  def params
26
14
  helpers.controller.params
27
15
  end
@@ -35,11 +23,15 @@ module Plutonium
35
23
  end
36
24
 
37
25
  delegate \
26
+ :resource_class,
27
+ :resource_record!,
28
+ :resource_record?,
38
29
  :resource_name,
39
30
  :resource_name_plural,
40
31
  :display_name_of,
41
32
  :resource_url_for,
42
33
  :current_user,
34
+ :current_parent,
43
35
  :current_definition,
44
36
  :current_query_object,
45
37
  :raw_resource_query_params,
@@ -19,16 +19,6 @@ module Plutonium
19
19
  select_tag(**attributes, class!: "", &)
20
20
  end
21
21
 
22
- def belongs_to_tag(**attributes, &)
23
- attributes[:data_controller] = tokens(attributes[:data_controller], "slim-select") # TODO: put this behind a config
24
- create_component(Components::BelongsTo, :belongs_to, **attributes, &)
25
- end
26
-
27
- def has_many_tag(**attributes, &)
28
- attributes[:data_controller] = tokens(attributes[:data_controller], "slim-select") # TODO: put this behind a config
29
- create_component(Components::HasMany, :has_many, **attributes, &)
30
- end
31
-
32
22
  def flatpickr_tag(**, &)
33
23
  create_component(Components::Flatpickr, :flatpickr, **, &)
34
24
  end
@@ -42,6 +32,28 @@ module Plutonium
42
32
  create_component(Components::Uppy, :uppy, **, &)
43
33
  end
44
34
  alias_method :file_tag, :uppy_tag
35
+
36
+ def secure_association_tag(**attributes, &)
37
+ attributes[:data_controller] = tokens(attributes[:data_controller], "slim-select") # TODO: put this behind a config
38
+ create_component(Components::SecureAssociation, :association, **attributes, &)
39
+ end
40
+ # preserve original methods with prefix
41
+ alias_method :basic_belongs_to_tag, :belongs_to_tag
42
+ alias_method :basic_has_many_tag, :has_many_tag
43
+ alias_method :basic_has_one_tag, :has_one_tag
44
+ # use new methods as defaults
45
+ alias_method :belongs_to_tag, :secure_association_tag
46
+ alias_method :has_many_tag, :secure_association_tag
47
+ alias_method :has_one_tag, :secure_association_tag
48
+
49
+ def secure_polymorphic_association_tag(**attributes, &)
50
+ attributes[:data_controller] = tokens(attributes[:data_controller], "slim-select") # TODO: put this behind a config
51
+ create_component(Components::SecurePolymorphicAssociation, :polymorphic_association, **attributes, &)
52
+ end
53
+ # preserve original methods with prefix
54
+ alias_method :basic_polymorphic_belongs_to_tag, :polymorphic_belongs_to_tag
55
+ # use new methods as defaults
56
+ alias_method :polymorphic_belongs_to_tag, :secure_polymorphic_association_tag
45
57
  end
46
58
 
47
59
  private