mirror of
https://github.com/we-promise/sure.git
synced 2026-09-08 16:14:23 +00:00
* feat(rules): support multiple tags in the set transaction tags action Fixes #3353. Reuses the existing DS::TagSelect multi-select tag picker (made generic via attribute:/show_label:) instead of a native <select multiple>, so the UX matches the rest of the app. Multiple tag ids are stored as a comma-separated string in the existing value column, keeping single-tag rows backward compatible with no migration. Also closes a read-modify-write race in SetTransactionTags#execute via with_lock. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(rules): address automated review findings on multi-tag actions - Fix data export/import: multi-tag actions were exported/imported as one opaque comma string, losing all but a bogus combined tag on restore. Each tag id is now resolved/reconstructed independently, with a backward-compatible scalar value_ref for single-tag actions. - Fix N+1 in Rule::Action#value_display (options queried once per tag). - Add aria-label to DS::TagSelect's trigger button when show_label is false, so the control keeps an accessible name. - Localize the "to" label in rule action rows (rules.actions.to_label). - Use a monotonic counter instead of Date.now() for nested form indices, closing a same-millisecond collision window. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(rules): batch tag lookups in multi-tag import resolution Avoids one find_by query per tag name when reconstructing multi-tag rule actions during import. * fix(rules): resolve jjmata review findings on multi-tag action - rules_controller.js: prefix the JS-side nested-form index counter with "new_" so it can never collide with the numeric indexes Rails assigns to already-persisted conditions/actions on an edit form. - data_exporter.rb: key the value_ref scalar/array decision off the number of tag ids on the action, not the number that still resolve, so a partially-orphaned multi-tag action keeps round-tripping as an array. - rule_import.rb: split comma-separated set_transaction_tags values into individual tag names during CSV rule import, matching the batched resolution already used by Family::DataImporter. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(rules): CSV-quote multi-tag names so commas don't split them CodeRabbit flagged that a tag name containing a comma (e.g. "Food, Dining") would be silently split into two tags when round-tripped through the comma-separated multi-tag value/CSV formats used by Family::DataExporter, Family::DataImporter, and RuleImport. Add Rule::Action.encode_multi_value_names/.decode_multi_value_names, backed by Ruby's CSV line quoting, and use them at all three call sites instead of a plain join(",")/split(","). A single name without a comma round-trips byte-identical to before, so existing exports and CSV rule templates are unaffected. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: GFR <248542187+gfr-free@users.noreply.github.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
73 lines
1.7 KiB
Ruby
73 lines
1.7 KiB
Ruby
class Rule::ActionExecutor
|
|
TYPES = [ "select", "multi_select", "function", "text" ]
|
|
|
|
def initialize(rule)
|
|
@rule = rule
|
|
end
|
|
|
|
def key
|
|
self.class.name.demodulize.underscore
|
|
end
|
|
|
|
def label
|
|
key.humanize
|
|
end
|
|
|
|
def type
|
|
"function"
|
|
end
|
|
|
|
def options
|
|
nil
|
|
end
|
|
|
|
def execute(scope, value: nil, ignore_attribute_locks: false, rule_run: nil)
|
|
raise NotImplementedError, "Action executor #{self.class.name} must implement #execute"
|
|
end
|
|
|
|
def as_json
|
|
{
|
|
type: type,
|
|
key: key,
|
|
label: label,
|
|
options: options
|
|
}
|
|
end
|
|
|
|
protected
|
|
# Helper method to track modified count during enrichment
|
|
# The block should return true if the resource was modified, false otherwise
|
|
# If the block doesn't return a value, we'll check previous_changes as a fallback
|
|
def count_modified_resources(scope)
|
|
modified_count = 0
|
|
scope.each do |resource|
|
|
# Yield the resource and capture the return value if the block returns one
|
|
block_result = yield resource
|
|
|
|
# If the block explicitly returned a boolean, use that
|
|
if block_result == true || block_result == false
|
|
was_modified = block_result
|
|
else
|
|
# Otherwise, check previous_changes as fallback
|
|
was_modified = resource.previous_changes.any?
|
|
|
|
# For Transaction resources, check the entry if the transaction itself wasn't modified
|
|
if !was_modified && resource.respond_to?(:entry)
|
|
entry = resource.entry
|
|
was_modified = entry&.previous_changes&.any? || false
|
|
end
|
|
end
|
|
|
|
modified_count += 1 if was_modified
|
|
end
|
|
modified_count
|
|
end
|
|
|
|
private
|
|
attr_reader :rule
|
|
|
|
def family
|
|
rule.family
|
|
end
|
|
end
|