FIX: composer save validation and tag assignment persistence#80
Open
jlzlt wants to merge 2 commits into
Open
Conversation
service:composer is a singleton that gets initialized early in the boot
process. On sites with multiple plugins, modifyClass("service:composer")
silently fails because the service is already cached by the time the
ratings initializer runs, so the save validation and draft observer were
never applied.
Moving the save validation into the existing modifyClass("model:composer")
block fixes the timing issue — model:composer is instantiated fresh each
time the composer opens, so the patch always applies. The _shouldSaveDraft
observer is dropped entirely; draft saves for ratings already work via the
serializeToDraft registration.
TagChooser's onChange passes full tag objects to the callback, not plain strings. updateTag was storing the raw object as obj.name, which got serialized as a nested hash in the POST body. Rails rejected it via strong parameters, so object_params[:name] came out nil, the blank check in Object.create returned false, and the save silently failed. Extract the name string from the tag object before storing it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #79
Two independent bugs fixed in this PR.
Bug 1 - Composer save validation silently broken on multi-plugin sites
modifyClass("service:composer", ...)was being called insidewithPluginApito intercept the composer'ssave()method and validate that all checked ratings have a value before submitting.On sites with multiple plugins,
service:composeris a singleton that gets initialized early in the boot process - before the ratings initializer runs.modifyClassdetects this and silently bails out, so the validation and the_shouldSaveDraftobserver were never applied. The composer would allow submitting with empty ratings, sending a 0 value to the server.Console message I received that triggered this PR:

Fix: Move the save validation into the existing
modifyClass("model:composer")block.model:composeris instantiated fresh each time the composer opens, so the patch always applies regardless of initialization order. The_shouldSaveDraftobserver is dropped - draft saves for ratings already work viaserializeToDraft.Bug 2 - Tag rating assignments not saved through admin UI
This is in reference to Issue #79.
When adding a tag assignment in the ratings admin panel, the save silently fails every time - meaning tag assignments have never persisted through the admin UI on Discourse versions from February 2026 onward.
The root cause: Discourse core commit 9e99066b changed
TagChooser's_onChangeto pass full tag objects to the callback instead of plain name strings.updateTagwas written for the old API and assumedtags[0]was a string. After the Discourse change,tags[0]became a full object, which got sent to the server as the tag name. Rails silently rejected it, causing the saveto fail with no error shown to the user.
Fix: Extract the tag name string from the TagChooser object before storing it. The fix handles both old and new Discourse versions - if
tags[0]is already a string it is used directly, otherwisenameis extracted from the object.