plutonium 0.18.4 → 0.18.6

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 (46) 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/core/controller.rb +2 -1
  18. data/lib/plutonium/resource/controller.rb +21 -7
  19. data/lib/plutonium/resource/controllers/authorizable.rb +8 -2
  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/routing/mapper_extensions.rb +2 -2
  30. data/lib/plutonium/routing/route_set_extensions.rb +7 -4
  31. data/lib/plutonium/ui/breadcrumbs.rb +4 -4
  32. data/lib/plutonium/ui/component/methods.rb +4 -12
  33. data/lib/plutonium/ui/form/base.rb +22 -10
  34. data/lib/plutonium/ui/form/components/secure_association.rb +112 -0
  35. data/lib/plutonium/ui/form/components/secure_polymorphic_association.rb +54 -0
  36. data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +0 -1
  37. data/lib/plutonium/ui/form/theme.rb +12 -1
  38. data/lib/plutonium/ui/page/show.rb +1 -1
  39. data/lib/plutonium/ui/page_header.rb +1 -1
  40. data/lib/plutonium/version.rb +1 -1
  41. data/package-lock.json +2 -2
  42. data/package.json +1 -1
  43. data/src/js/controllers/slim_select_controller.js +3 -1
  44. metadata +11 -4
  45. data/lib/plutonium/ui/form/components/belongs_to.rb +0 -66
  46. data/lib/plutonium/ui/form/components/has_many.rb +0 -66
@@ -1,4 +1,4 @@
1
- <%= render_component :breadcrumbs, resource_class:, parent: current_parent, resource: resource_record %>
1
+ <%= render_component :breadcrumbs, resource_class:, parent: current_parent, resource: resource_record! %>
2
2
 
3
3
  <%= render_component :dyna_frame_content do %>
4
4
  <%= render "interactive_action_form", interactive_action: current_interactive_action %>
@@ -1,4 +1,4 @@
1
- <%= render_component :breadcrumbs, resource_class:, parent: current_parent, resource: resource_record %>
1
+ <%= render_component :breadcrumbs, resource_class:, parent: current_parent, resource: resource_record! %>
2
2
 
3
3
  <%= render_component :dyna_frame_content do %>
4
4
  <%= render "interactive_action_form", interactive_action: current_interactive_action %>
@@ -11,7 +11,6 @@ module Pu
11
11
 
12
12
  desc "Eject layout views into your own project"
13
13
 
14
- class_option :dest, type: :string
15
14
  class_option :rodauth, type: :boolean
16
15
 
17
16
  def start
@@ -28,7 +27,7 @@ module Pu
28
27
  private
29
28
 
30
29
  def destination_portal
31
- @destination_portal || select_portal(options[:dest], msg: "Select destination portal")
30
+ portal_option(:dest, prompt: "Select destination portal")
32
31
  end
33
32
 
34
33
  def copy_file(source_path, destination_path)
@@ -11,8 +11,6 @@ module Pu
11
11
 
12
12
  desc "Eject layout shell (i.e header, sidebar) into your own project"
13
13
 
14
- class_option :dest, type: :string
15
-
16
14
  def start
17
15
  destination_dir = (destination_portal == "main_app") ? "app/views/" : "packages/#{destination_portal}/app/views"
18
16
  [
@@ -28,7 +26,7 @@ module Pu
28
26
  private
29
27
 
30
28
  def destination_portal
31
- @destination_portal || select_portal(options[:dest], msg: "Select destination portal")
29
+ portal_option(:dest, prompt: "Select destination portal")
32
30
  end
33
31
 
34
32
  def copy_file(source_path, destination_path)
@@ -11,6 +11,10 @@ module PlutoniumGenerators
11
11
  say format_log(msg, :info), :blue
12
12
  end
13
13
 
14
+ def warn(msg)
15
+ say format_log(msg, :warn), :yellow
16
+ end
17
+
14
18
  def success(msg)
15
19
  say format_log(msg, :success), :green
16
20
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlutoniumGenerators
4
+ module Concerns
5
+ module PackageSelector
6
+ def self.included(base)
7
+ base.send :class_option, :src, type: :string, desc: "The source package if applicable"
8
+ base.send :class_option, :dest, type: :string, desc: "The destination package if applicable"
9
+ end
10
+
11
+ private
12
+
13
+ def reserved_packages
14
+ %w[core reactor app main plutonium pluton8 plutonate]
15
+ end
16
+
17
+ def validate_package_name(package_name)
18
+ package_name = package_name.underscore
19
+ error("Package name is reserved\n\n#{reserved_packages.join "\n"}") if reserved_packages.include?(package_name)
20
+ error("Package name cannot end in `_app` or `_portal`") if /(_app|_portal)$/i.match?(package_name)
21
+ end
22
+
23
+ def available_packages
24
+ @available_packages ||= begin
25
+ packages = Dir["packages/*"].map { |dir| dir.gsub "packages/", "" }
26
+ packages - reserved_packages
27
+ end
28
+ end
29
+
30
+ def available_portals
31
+ @available_portals ||= ["main_app"] + available_packages.select { |pkg| pkg.ends_with?("_app") || pkg.ends_with?("_portal") }.sort
32
+ end
33
+
34
+ def available_features
35
+ @available_features ||= ["main_app"] + available_packages.select { |pkg| !(pkg.ends_with?("_app") || pkg.ends_with?("_portal")) }.sort
36
+ end
37
+
38
+ def select_package(selected_package = nil, msg: "Select package", pkgs: nil)
39
+ pkgs ||= available_packages
40
+ if pkgs.include?(selected_package)
41
+ selected_package
42
+ else
43
+ prompt.select(msg, pkgs)
44
+ end
45
+ end
46
+
47
+ def select_feature(selected_package = nil, msg: "Select feature")
48
+ select_package(selected_package, msg: msg, pkgs: available_features)
49
+ end
50
+
51
+ def feature_option(name, prompt: nil, option_key: nil)
52
+ # Get stored value or command line option
53
+ ivar = :"@#{name}_feature_option"
54
+ return instance_variable_get(ivar) if instance_variable_defined?(ivar)
55
+
56
+ # Validate option or prompt user
57
+ option_key ||= name
58
+ value = select_feature(options[option_key], msg: prompt || "Select #{name} feature")
59
+ instance_variable_set(ivar, value)
60
+ value
61
+ end
62
+
63
+ def select_portal(selected_package = nil, msg: "Select portal")
64
+ select_package(selected_package, msg: msg, pkgs: available_portals)
65
+ end
66
+
67
+ def portal_option(name, prompt: nil, option_key: nil)
68
+ # Get stored value or command line option
69
+ ivar = :"@#{name}_portal_option"
70
+ return instance_variable_get(ivar) if instance_variable_defined?(ivar)
71
+
72
+ # Validate option or prompt user
73
+ option_key ||= name
74
+ value = select_portal(options[option_key], msg: prompt || "Select #{name} portal")
75
+ instance_variable_set(ivar, value)
76
+ value
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlutoniumGenerators
4
+ module Concerns
5
+ module ResourceSelector
6
+ def self.included(base)
7
+ # base.send :class_option, :resources, type: :array, desc: "List of resource model names if applicable"
8
+ base.send :argument, :resources, type: :array, optional: true, default: [],
9
+ desc: "List of model names if applicable"
10
+ end
11
+
12
+ private
13
+
14
+ def available_resources(source_module)
15
+ Plutonium.eager_load_rails!
16
+
17
+ source_module.constantize.descendants.reject do |resource_klass|
18
+ next true if resource_klass.abstract_class?
19
+ next true if source_module == "ApplicationRecord" &&
20
+ resource_klass.ancestors.any? { |ancestor| ancestor.to_s.end_with?("::ResourceRecord") }
21
+ end.map(&:to_s).sort
22
+ end
23
+
24
+ def select_resources(source_module, prompt: "Select resources")
25
+ resources = available_resources(source_module)
26
+ error "No resources found" if resources.blank?
27
+
28
+ self.prompt.multi_select(prompt, resources)
29
+ end
30
+
31
+ def resources_selection(prompt: nil)
32
+ ivar = :@resources_selection
33
+ return instance_variable_get(ivar) if instance_variable_defined?(ivar)
34
+
35
+ # Convert comma-separated string to array if from command line
36
+ value = resources.map(&:classify)
37
+ if value.empty?
38
+ source_feature = feature_option :src, prompt: "Select source feature"
39
+ source_module = (source_feature == "main_app") ? "ApplicationRecord" : "#{source_feature.camelize}::ResourceRecord"
40
+ value = select_resources(source_module, prompt: prompt || "Select #{source_module} resources")
41
+ end
42
+
43
+ instance_variable_set(ivar, value)
44
+ value
45
+ end
46
+ end
47
+ end
48
+ end
@@ -14,51 +14,11 @@ module PlutoniumGenerators
14
14
  base.send :class_option, :interactive, type: :boolean, desc: "Show prompts. Default: true"
15
15
  base.send :class_option, :bundle, type: :boolean, desc: "Run bundle after setup. Default: true"
16
16
  base.send :class_option, :lint, type: :boolean, desc: "Run linter after generation. Default: false"
17
- end
18
-
19
- protected
20
-
21
- def reserved_packages
22
- %w[core reactor app main plutonium pluton8 plutonate]
23
- end
24
-
25
- def validate_package_name(package_name)
26
- package_name = package_name.underscore
27
- error("Package name is reserved\n\n#{reserved_packages.join "\n"}") if reserved_packages.include?(package_name)
28
- error("Package name cannot end in `_app` or `_portal`") if /(_app|_portal)$/i.match?(package_name)
29
- end
30
-
31
- def available_packages
32
- @available_packages ||= begin
33
- packages = Dir["packages/*"].map { |dir| dir.gsub "packages/", "" }
34
- packages - reserved_packages
35
- end
36
- end
37
17
 
38
- def available_apps
39
- @available_apps ||= ["main_app"] + available_packages.select { |pkg| pkg.ends_with?("_app") || pkg.ends_with?("_portal") }.sort
18
+ base.include Concerns::PackageSelector
40
19
  end
41
20
 
42
- def available_features
43
- @available_features ||= ["main_app"] + available_packages.select { |pkg| !(pkg.ends_with?("_app") || pkg.ends_with?("_portal")) }.sort
44
- end
45
-
46
- def select_package(selected_package = nil, msg: "Select package", pkgs: nil)
47
- pkgs ||= available_packages
48
- if pkgs.include?(selected_package)
49
- selected_package
50
- else
51
- prompt.select(msg, pkgs)
52
- end
53
- end
54
-
55
- def select_portal(selected_package = nil, msg: "Select portal")
56
- select_package(selected_package, msg: msg, pkgs: available_apps)
57
- end
58
-
59
- def select_feature(selected_package = nil, msg: "Select feature")
60
- select_package(selected_package, msg: msg, pkgs: available_features)
61
- end
21
+ protected
62
22
 
63
23
  # ####################
64
24
 
@@ -13,8 +13,6 @@ module PlutoniumGenerators
13
13
  remove_task :create_module_file
14
14
  # remove_task :check_class_collision
15
15
 
16
- class_option :dest, type: :string
17
-
18
16
  # def check_class_collision # :doc:
19
17
  # class_collisions "#{options[:prefix]}#{name}#{options[:suffix]}"
20
18
  # end
@@ -41,7 +39,6 @@ module PlutoniumGenerators
41
39
  def name
42
40
  @pu_name ||= begin
43
41
  @original_name = @name
44
- @selected_destination_feature = select_feature selected_destination_feature, msg: "Select destination feature"
45
42
  @name = [main_app? ? nil : selected_destination_feature.underscore, super.singularize.underscore].compact.join "/"
46
43
  set_destination_root!
47
44
  @name
@@ -57,7 +54,7 @@ module PlutoniumGenerators
57
54
  end
58
55
 
59
56
  def selected_destination_feature
60
- @selected_destination_feature || options[:dest]
57
+ feature_option :dest, prompt: "Select destination feature"
61
58
  end
62
59
 
63
60
  def set_destination_root!
@@ -6,26 +6,20 @@ module Pu
6
6
  module Res
7
7
  class ConnGenerator < Rails::Generators::Base
8
8
  include PlutoniumGenerators::Generator
9
+ include PlutoniumGenerators::Concerns::ResourceSelector
9
10
 
10
11
  source_root File.expand_path("templates", __dir__)
11
12
 
12
- desc "Create a connection between a resource and an app"
13
+ desc(
14
+ "Create a connection between a resource and a portal\n\n" \
15
+ "e.g. rails g pu:res:conn todo --dest=dashboard_portal"
16
+ )
13
17
 
14
18
  # argument :name
15
19
 
16
20
  def start
17
- source_feature = select_feature msg: "Select source feature"
18
- source_module = (source_feature == "main_app") ? "ApplicationRecord" : "#{source_feature.camelize}::ResourceRecord"
19
-
20
- Plutonium.eager_load_rails!
21
- available_resources = source_module.constantize.descendants.reject do |model|
22
- next true if model.abstract_class?
23
- next true if source_module == "ApplicationRecord" && model.ancestors.any? { |ancestor| ancestor.to_s.end_with?("::ResourceRecord") }
24
- end.map(&:to_s).sort
25
- error "No resources found" if available_resources.blank?
26
- selected_resources = prompt.multi_select("Select resources", available_resources)
27
-
28
- @app_namespace = select_portal.camelize
21
+ selected_resources = resources_selection
22
+ @app_namespace = portal_option(:dest, prompt: "Select destination portal").camelize
29
23
 
30
24
  selected_resources.each do |resource|
31
25
  @resource_class = resource
@@ -97,13 +91,7 @@ module Pu
97
91
 
98
92
  def attributes
99
93
  resource_klass = resource_class.constantize
100
- unwanted_attrs = [
101
- resource_klass.primary_key.to_sym, # primary_key
102
- :created_at, :updated_at # timestamps
103
- ]
104
94
  resource_klass.content_columns.filter_map { |col|
105
- next if unwanted_attrs.include? col.name.to_sym
106
-
107
95
  PlutoniumGenerators::ModelGeneratorBase::GeneratedAttribute.parse resource_class, "#{col.name}:#{col.type}"
108
96
  }
109
97
  rescue ActiveRecord::StatementInvalid
@@ -116,11 +104,11 @@ module Pu
116
104
  end
117
105
 
118
106
  def policy_attributes_for_create
119
- default_policy_attributes
107
+ default_policy_attributes - [:created_at, :updated_at]
120
108
  end
121
109
 
122
110
  def policy_attributes_for_read
123
- default_policy_attributes + [:created_at, :updated_at]
111
+ default_policy_attributes
124
112
  end
125
113
  end
126
114
  end
@@ -4,6 +4,7 @@ require_relative "../../lib/plutonium_generators"
4
4
 
5
5
  module Pu
6
6
  module Res
7
+ # run `rails g pu:res:scaffold existing_resource` without any arguments to import an existing resource
7
8
  class ScaffoldGenerator < PlutoniumGenerators::ModelGeneratorBase
8
9
  include PlutoniumGenerators::Generator
9
10
 
@@ -17,9 +18,13 @@ module Pu
17
18
  return unless options[:model]
18
19
 
19
20
  model_class = class_name.safe_constantize
20
- if model_class.present? && attributes.empty? && prompt.yes?("Existing model class found. Do you want to import its attributes?")
21
- attributes_str = model_class.content_columns.map { |col| "#{col.name}:#{col.type}" }
22
- self.attributes = parse_attributes_internal!(attributes_str)
21
+ if model_class.present?
22
+ if attributes.empty?
23
+ attributes_str = model_class.content_columns.map { |col| "#{col.name}:#{col.type}" }
24
+ self.attributes = parse_attributes_internal!(attributes_str)
25
+ else
26
+ warn("Overwriting existing resource. You can leave out the attributes to import an existing resource.")
27
+ end
23
28
  end
24
29
  end
25
30
 
@@ -56,11 +61,11 @@ module Pu
56
61
  end
57
62
 
58
63
  def policy_attributes_for_create
59
- default_policy_attributes
64
+ default_policy_attributes - [:created_at, :updated_at]
60
65
  end
61
66
 
62
67
  def policy_attributes_for_read
63
- default_policy_attributes + [:created_at, :updated_at]
68
+ default_policy_attributes
64
69
  end
65
70
  end
66
71
  end
@@ -70,7 +70,8 @@ module Plutonium
70
70
  else
71
71
  controller_chain << element.class.to_s.pluralize
72
72
  if index == args.length - 1
73
- url_args[:id] = element.to_param
73
+ resource_route_config = current_engine.routes.resource_route_config_for(element.model_name.plural)[0]
74
+ url_args[:id] = element.to_param unless resource_route_config[:route_type] == :resource
74
75
  url_args[:action] ||= :show
75
76
  else
76
77
  url_args[element.model_name.singular_route_key.to_sym] = element.to_param
@@ -19,7 +19,7 @@ module Plutonium
19
19
  # https://github.com/ddnexus/pagy/blob/master/docs/extras/headers.md#headers
20
20
  after_action { pagy_headers_merge(@pagy) if @pagy }
21
21
 
22
- helper_method :current_parent, :resource_record, :resource_param_key, :resource_class
22
+ helper_method :current_parent, :resource_record!, :resource_record?, :resource_param_key, :resource_class
23
23
  end
24
24
 
25
25
  class_methods do
@@ -49,11 +49,25 @@ module Plutonium
49
49
  self.class.resource_class
50
50
  end
51
51
 
52
- # Returns the resource record based on path parameters
53
- # @return [ActiveRecord::Base, nil] The resource record
54
- def resource_record
55
- @resource_record ||= current_authorized_scope.from_path_param(params[:id]).first! if params[:id]
56
- @resource_record
52
+ def resource_record_relation
53
+ @resource_record_relation ||= begin
54
+ resource_route_config = current_engine.routes.resource_route_config_for(resource_class.model_name.plural)[0]
55
+ if resource_route_config[:route_type] == :resource
56
+ current_authorized_scope
57
+ elsif params[:id]
58
+ current_authorized_scope.from_path_param(params[:id])
59
+ else
60
+ current_authorized_scope.none
61
+ end
62
+ end
63
+ end
64
+
65
+ def resource_record!
66
+ @resource_record ||= resource_record_relation.first!
67
+ end
68
+
69
+ def resource_record?
70
+ @resource_record ||= resource_record_relation.first
57
71
  end
58
72
 
59
73
  # Returns the submitted resource parameters
@@ -103,7 +117,7 @@ module Plutonium
103
117
  # Applies submitted resource params if they have been passed
104
118
  def maybe_apply_submitted_resource_params!
105
119
  ensure_get_request
106
- resource_record.attributes = submitted_resource_params if params[resource_param_key]
120
+ resource_record!.attributes = submitted_resource_params if params[resource_param_key]
107
121
  end
108
122
 
109
123
  # Returns the current parent based on path parameters
@@ -12,7 +12,7 @@ module Plutonium
12
12
  # include Plutonium::Resource::Controllers::Authorizable
13
13
  # end
14
14
  #
15
- # @note This module assumes the existence of methods like `resource_record`,
15
+ # @note This module assumes the existence of methods like `resource_record!`,
16
16
  # `resource_class`, `current_parent`, and `entity_scope_for_authorize`.
17
17
  #
18
18
  # @see ActionPolicy
@@ -144,7 +144,13 @@ module Plutonium
144
144
  #
145
145
  # @return [Object] the subject for the policy (either resource_record or resource_class)
146
146
  def current_policy_subject
147
- resource_record || resource_class
147
+ # We have an "inconsistency" here where resource_record?
148
+ # will return an actual record instead of nil for routes such as :new when dealing with singular resources.
149
+ # It impacts mainly attribute policies, such as when getting the allowed attributes for forms.
150
+ # But while it is an an inconsistency, I believe it is expected behaviour.
151
+ # You did mark the resource as singular after all.
152
+ # So you should disable :create? in your policy when a record exists.
153
+ resource_record? || resource_class
148
154
  end
149
155
  end
150
156
  end
@@ -21,8 +21,8 @@ module Plutonium
21
21
 
22
22
  # GET /resources/1(.{format})
23
23
  def show
24
- authorize_current! resource_record
25
- set_page_title resource_record.to_label.titleize
24
+ authorize_current! resource_record!
25
+ set_page_title resource_record!.to_label.titleize
26
26
 
27
27
  render :show
28
28
  end
@@ -46,7 +46,7 @@ module Plutonium
46
46
  @resource_record = resource_class.new resource_params
47
47
 
48
48
  respond_to do |format|
49
- if resource_record.save
49
+ if resource_record!.save
50
50
  format.html do
51
51
  redirect_to redirect_url_after_submit,
52
52
  notice: "#{resource_class.model_name.human} was successfully created."
@@ -57,7 +57,7 @@ module Plutonium
57
57
  render :new, status: :unprocessable_entity
58
58
  end
59
59
  format.any do
60
- @errors = resource_record.errors
60
+ @errors = resource_record!.errors
61
61
  render "errors", status: :unprocessable_entity
62
62
  end
63
63
  end
@@ -66,8 +66,8 @@ module Plutonium
66
66
 
67
67
  # GET /resources/1/edit
68
68
  def edit
69
- authorize_current! resource_record
70
- set_page_title "Update #{resource_record.to_label.titleize}"
69
+ authorize_current! resource_record!
70
+ set_page_title "Update #{resource_record!.to_label.titleize}"
71
71
 
72
72
  maybe_apply_submitted_resource_params!
73
73
 
@@ -76,11 +76,11 @@ module Plutonium
76
76
 
77
77
  # PATCH/PUT /resources/1(.{format})
78
78
  def update
79
- authorize_current! resource_record
80
- set_page_title "Update #{resource_record.to_label.titleize}"
79
+ authorize_current! resource_record!
80
+ set_page_title "Update #{resource_record!.to_label.titleize}"
81
81
 
82
82
  respond_to do |format|
83
- if resource_record.update(resource_params)
83
+ if resource_record!.update(resource_params)
84
84
  format.html do
85
85
  redirect_to redirect_url_after_submit, notice: "#{resource_class.model_name.human} was successfully updated.",
86
86
  status: :see_other
@@ -91,7 +91,7 @@ module Plutonium
91
91
  render :edit, status: :unprocessable_entity
92
92
  end
93
93
  format.any do
94
- @errors = resource_record.errors
94
+ @errors = resource_record!.errors
95
95
  render "errors", status: :unprocessable_entity
96
96
  end
97
97
  end
@@ -100,10 +100,10 @@ module Plutonium
100
100
 
101
101
  # DELETE /resources/1(.{format})
102
102
  def destroy
103
- authorize_current! resource_record
103
+ authorize_current! resource_record!
104
104
 
105
105
  respond_to do |format|
106
- resource_record.destroy
106
+ resource_record!.destroy
107
107
 
108
108
  format.html do
109
109
  redirect_to redirect_url_after_destroy,
@@ -112,11 +112,11 @@ module Plutonium
112
112
  format.json { head :no_content }
113
113
  rescue ActiveRecord::InvalidForeignKey
114
114
  format.html do
115
- redirect_to resource_url_for(resource_record),
115
+ redirect_to resource_url_for(resource_record!),
116
116
  alert: "#{resource_class.model_name.human} is referenced by other records."
117
117
  end
118
118
  format.any do
119
- @errors = ActiveModel::Errors.new resource_record
119
+ @errors = ActiveModel::Errors.new resource_record!
120
120
  @errors.add :base, :existing_references, message: "is referenced by other records"
121
121
 
122
122
  render "errors", status: :unprocessable_entity
@@ -133,9 +133,9 @@ module Plutonium
133
133
 
134
134
  url = case preferred_action_after_submit
135
135
  when "show"
136
- resource_url_for(resource_record) if current_policy.allowed_to? :show?
136
+ resource_url_for(resource_record!) if current_policy.allowed_to? :show?
137
137
  when "edit"
138
- resource_url_for(resource_record, action: :edit) if current_policy.allowed_to? :edit?
138
+ resource_url_for(resource_record!, action: :edit) if current_policy.allowed_to? :edit?
139
139
  when "new"
140
140
  resource_url_for(resource_class, action: :new) if current_policy.allowed_to? :new?
141
141
  when "index"
@@ -144,7 +144,7 @@ module Plutonium
144
144
  # ensure we have a valid value
145
145
  session[:action_after_submit_preference] = "show"
146
146
  end
147
- url || resource_url_for(resource_record)
147
+ url || resource_url_for(resource_record!)
148
148
  end
149
149
 
150
150
  def redirect_url_after_destroy
@@ -42,7 +42,7 @@ module Plutonium
42
42
  if outcome.success?
43
43
  outcome.to_response.process(self) do |value|
44
44
  respond_to do |format|
45
- return_url = redirect_url_after_action_on(resource_record)
45
+ return_url = redirect_url_after_action_on(resource_record!)
46
46
  format.any { redirect_to return_url, status: :see_other }
47
47
  if helpers.current_turbo_frame == "modal"
48
48
  format.turbo_stream do
@@ -202,7 +202,7 @@ module Plutonium
202
202
 
203
203
  def authorize_interactive_record_action!
204
204
  interactive_resource_action = params[:interactive_action]&.to_sym
205
- authorize_current! resource_record, to: :"#{interactive_resource_action}?"
205
+ authorize_current! resource_record!, to: :"#{interactive_resource_action}?"
206
206
  end
207
207
 
208
208
  def authorize_interactive_resource_action!
@@ -216,7 +216,7 @@ module Plutonium
216
216
 
217
217
  def build_interactive_record_action_interaction
218
218
  @interaction = current_interactive_action.interaction.new(view_context:)
219
- @interaction.attributes = interaction_params.merge(resource: resource_record)
219
+ @interaction.attributes = interaction_params.merge(resource: resource_record!)
220
220
  @interaction
221
221
  end
222
222
 
@@ -36,10 +36,10 @@ module Plutonium
36
36
  end
37
37
 
38
38
  def build_detail
39
- current_definition.detail_class.new(resource_record, resource_fields: presentable_attributes, resource_associations: permitted_associations, resource_definition: current_definition)
39
+ current_definition.detail_class.new(resource_record!, resource_fields: presentable_attributes, resource_associations: permitted_associations, resource_definition: current_definition)
40
40
  end
41
41
 
42
- def build_form(record = resource_record)
42
+ def build_form(record = resource_record!)
43
43
  current_definition.form_class.new(record, resource_fields: submittable_attributes, resource_definition: current_definition)
44
44
  end
45
45
  end