plutonium 0.57.0 → 0.58.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8780fef2990ef53370f7883f0b5d5ed262744ca639b26710a8e8a002765f4df0
4
- data.tar.gz: 695ed4654c732d10aa14af00ad9c345627a1ffb624de90d5fd475ca3f78daa77
3
+ metadata.gz: 0dbc2397e69b01d4570b44352873ed678884596e42fb6e9187d73c757ef12cb5
4
+ data.tar.gz: '049b9ee55a141c38c0544de18a2a39ed02e22d56aeb3f6076fdff4938bb1eff4'
5
5
  SHA512:
6
- metadata.gz: b112625485b6e1ff480c28af736227df6243d8fb890036254e5b2c4e7b9ad2e3825083ed69771c2cd1c199292dcc5c9d112821951c22324ffceeae5889839bbe
7
- data.tar.gz: 9970143c56fdc7270294413094bb9cb48495db02302272dd69e56b57dbb0a37bb91311b5634da60052b6cca6542044567b9fb698f23fa42b228c8146e9d3bc80
6
+ metadata.gz: b47bf5a27f2a89a4ea705baf78cb34bd17bdb9270bdd386e5d0fa30e601744632945ca451ba019ad4788626702d667a67b848306c4fcc38d29ebd70bbbbc9c12
7
+ data.tar.gz: 02ee1e16fe6fc058f14295a54d2a5db2e52c9a65f2d26d5ab988a1b9bdb379c7d1eb32d2b1cc24482c1bae19628e0629bc5a536d64865a893d7b2291ab0e1389
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.58.0] - 2026-06-10
2
+
3
+ ### 🐛 Bug Fixes
4
+
5
+ - *(rodauth)* Set url_options directly on ActionMailer::Base instead of config
6
+ - *(interaction)* Short-circuit call with failure when validation fails
7
+ - *(form)* Pre-populate extraction record so conditioned selects resolve correctly
8
+ - *(invites)* Use after_commit to avoid orphaned email jobs on rollback
1
9
  ## [0.57.0] - 2026-06-09
2
10
 
3
11
  ### 🚀 Features
@@ -1,17 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Rails.application.config.after_initialize do
4
- default_url = ENV["RAILS_DEFAULT_URL"]
5
- if default_url && Rails.application.config.action_mailer.default_url_options.blank?
6
- uri = URI.parse(default_url)
7
- Rails.application.config.action_mailer.default_url_options = {
8
- host: uri.host,
9
- port: uri.port,
10
- protocol: uri.scheme
11
- }
12
- end
3
+ if (default_url = ENV["RAILS_DEFAULT_URL"])
4
+ uri = URI.parse(default_url)
5
+ default_port = (uri.scheme == "https") ? 443 : 80
6
+ url_options = {host: uri.host, protocol: uri.scheme}
7
+ .tap { |opts| opts[:port] = uri.port if uri.port != default_port }
13
8
 
14
- if Rails.application.routes.default_url_options.blank?
15
- Rails.application.routes.default_url_options = Rails.application.config.action_mailer.default_url_options
16
- end
9
+ ActionMailer::Base.default_url_options = url_options if ActionMailer::Base.default_url_options.blank?
10
+ Rails.application.routes.default_url_options = url_options if Rails.application.routes.default_url_options.blank?
17
11
  end
@@ -70,16 +70,14 @@ module Plutonium
70
70
  #
71
71
  # @return [Plutonium::Interaction::Outcome] The result of the interaction.
72
72
  def call
73
- if valid?
74
- outcome = execute
75
- unless outcome.is_a?(Plutonium::Interaction::Outcome)
76
- raise "#{self.class}#execute must return an instance of Plutonium::Interaction::Outcome.\n" \
77
- "#{outcome.inspect} received instead"
78
- end
79
- outcome
80
- else
81
- failure.with_message("An error occurred")
73
+ return failure unless valid?
74
+
75
+ outcome = execute
76
+ unless outcome.is_a?(Plutonium::Interaction::Outcome)
77
+ raise "#{self.class}#execute must return an instance of Plutonium::Interaction::Outcome.\n" \
78
+ "#{outcome.inspect} received instead"
82
79
  end
80
+ outcome
83
81
  end
84
82
 
85
83
  private
@@ -41,7 +41,7 @@ module Plutonium
41
41
 
42
42
  # Callbacks
43
43
  before_validation :set_token_defaults, on: :create
44
- after_create :send_invitation_email
44
+ after_commit :send_invitation_email, on: :create
45
45
 
46
46
  # Core validations
47
47
  validates :email, presence: true
@@ -146,6 +146,21 @@ module Plutonium
146
146
  # Pass form_action: false to prevent form from trying to generate URL (cloned record has id: nil)
147
147
  extraction_record = resource_record?&.dup || resource_class.new
148
148
  @submitted_resource_params ||= begin
149
+ # Pre-populate from submitted params so condition: procs evaluate against submitted
150
+ # values during extraction. Without this, a select whose choices: depend on a sibling
151
+ # attribute would see nil for that sibling (fresh/cloned record) and resolve to empty
152
+ # choices, causing AcceptsChoices to nullify a valid submitted value.
153
+ # attribute_names covers DB columns and `attribute :` declarations.
154
+ # The union with respond_to? also covers attr_accessor virtual attributes.
155
+ submitted = params[resource_param_key]&.to_unsafe_h || {}
156
+ base_keys = extraction_record.attribute_names.map(&:to_s)
157
+ # Also include attr_accessor virtual attributes not in attribute_names.
158
+ # Exclude AR association writers — they expect object instances, not param strings.
159
+ extra_keys = (submitted.keys.map(&:to_s) - base_keys).select { |k|
160
+ extraction_record.respond_to?("#{k}=") &&
161
+ extraction_record.class.reflect_on_association(k.to_sym).nil?
162
+ }
163
+ extraction_record.assign_attributes(submitted.slice(*(base_keys | extra_keys)))
149
164
  extracted = build_form(extraction_record, form_action: false)
150
165
  .extract_input(params, view_context:)[resource_param_key.to_sym].compact
151
166
  clean_structured_inputs(current_definition, extracted)
@@ -262,6 +262,17 @@ module Plutonium
262
262
  elsif action.bulk_action?
263
263
  instance.resources = interactive_bulk
264
264
  end
265
+ # Pre-populate sibling attributes from submitted params before rendering
266
+ # the form for extraction. When a select input's `choices:` depends on a
267
+ # sibling attribute and `condition:` guards it, the condition evaluates to
268
+ # false on a fresh instance (sibling is nil), making AcceptsChoices
269
+ # validate against an empty choices list and nullify a valid submitted
270
+ # value. Pre-populating lets conditions evaluate against submitted values,
271
+ # so the real select (with correct choices) is used for extraction.
272
+ submitted = params[:interaction]&.to_unsafe_h || {}
273
+ base_keys = instance.attribute_names.map(&:to_s) - %w[resource resources]
274
+ extra_keys = submitted.keys.map(&:to_s).select { |k| instance.respond_to?("#{k}=") } - %w[resource resources]
275
+ instance.assign_attributes(submitted.slice(*(base_keys | extra_keys)))
265
276
  extracted = interaction
266
277
  .build_form(instance)
267
278
  .extract_input(params, view_context:)[:interaction]
@@ -1,5 +1,5 @@
1
1
  module Plutonium
2
- VERSION = "0.57.0"
2
+ VERSION = "0.58.0"
3
3
  NEXT_MAJOR_VERSION = VERSION.split(".").tap { |v|
4
4
  v[1] = v[1].to_i + 1
5
5
  v[2] = 0
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radioactive-labs/plutonium",
3
- "version": "0.57.0",
3
+ "version": "0.58.0",
4
4
  "description": "Build production-ready Rails apps in minutes, not days. Convention-driven, fully customizable, AI-ready.",
5
5
  "type": "module",
6
6
  "main": "src/js/core.js",
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plutonium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.57.0
4
+ version: 0.58.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Froelich
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-06-09 00:00:00.000000000 Z
10
+ date: 2026-06-10 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: zeitwerk