mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 03:54:08 +00:00
FIX Read-Modify-Write issue with dynamic fields (#290)
* FIX Read-Modify-Write issue with dynamic fields Ruby caching + queueing updates might cause some dynamic fields to not be updated. * Small fix for true dynamic fields * Add suite of tests for new settings page * Treat nil values as deletions to keep the hash clean * Test fix
This commit is contained in:
@@ -28,6 +28,9 @@ class Settings::ProvidersController < ApplicationController
|
||||
|
||||
updated_fields = []
|
||||
|
||||
# This hash will store only the updates for dynamic (non-declared) fields
|
||||
dynamic_updates = {}
|
||||
|
||||
# Perform all updates within a transaction for consistency
|
||||
Setting.transaction do
|
||||
provider_params.each do |param_key, param_value|
|
||||
@@ -44,10 +47,42 @@ class Settings::ProvidersController < ApplicationController
|
||||
next
|
||||
end
|
||||
|
||||
# Set the value using dynamic hash-style access
|
||||
Setting[field.setting_key] = value
|
||||
key_str = field.setting_key.to_s
|
||||
|
||||
# Check if the setting is a declared field in setting.rb
|
||||
# Use method_defined? to check if the setter actually exists on the singleton class,
|
||||
# not just respond_to? which returns true for dynamic fields due to respond_to_missing?
|
||||
if Setting.singleton_class.method_defined?("#{key_str}=")
|
||||
# If it's a declared field (e.g., openai_model), set it directly.
|
||||
# This is safe and uses the proper setter.
|
||||
Setting.public_send("#{key_str}=", value)
|
||||
else
|
||||
# If it's a dynamic field, add it to our batch hash
|
||||
# to avoid the Read-Modify-Write conflict.
|
||||
dynamic_updates[key_str] = value
|
||||
end
|
||||
|
||||
updated_fields << param_key
|
||||
end
|
||||
|
||||
# Now, if we have any dynamic updates, apply them all at once
|
||||
if dynamic_updates.any?
|
||||
# 1. READ the current hash once
|
||||
current_dynamic = Setting.dynamic_fields.dup
|
||||
|
||||
# 2. MODIFY by merging changes
|
||||
# Treat nil values as deletions to keep the hash clean
|
||||
dynamic_updates.each do |key, value|
|
||||
if value.nil?
|
||||
current_dynamic.delete(key)
|
||||
else
|
||||
current_dynamic[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
# 3. WRITE the complete, merged hash back once
|
||||
Setting.dynamic_fields = current_dynamic
|
||||
end
|
||||
end
|
||||
|
||||
if updated_fields.any?
|
||||
@@ -61,6 +96,9 @@ class Settings::ProvidersController < ApplicationController
|
||||
rescue => error
|
||||
Rails.logger.error("Failed to update provider settings: #{error.message}")
|
||||
flash.now[:alert] = "Failed to update provider settings: #{error.message}"
|
||||
# Set @provider_configurations so the view can render properly
|
||||
Provider::Factory.ensure_adapters_loaded
|
||||
@provider_configurations = Provider::ConfigurationRegistry.all
|
||||
render :show, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user