שגיאת `NoMethodError in TopicsController#show` לאחר מיזוג נושאים

סיכום מבוסס בינה מלאכותית

A bug report by blu3id details a NoMethodError: undefined method 'category_id' for nil occurring in the Discourse Calendar plugin (version 0.5) after merging topics and deleting a merged post. The error renders the target topic inaccessible, specifically tracing back to plugins/discourse-calendar/app/serializers/discourse_post_event/event_serializer.rb. The issue is classified as Low Priority but High Severity.

2sam acknowledges the report and adds the pr-welcome tag to encourage contributions. Michael12 confirms experiencing a similar issue and suggests disabling the plugin as a temporary workaround.

JammyDodger provides a simplified reproduction scenario: merging a topic containing a calendar event into another topic causes the event to no longer be the original post (OP). Subsequently deleting the target topic triggers the server error. JammyDodger proposes that the fix should prevent merges that would displace an event from the OP position, noting that merging an event into a non-OP position is already blocked with a different error. They suggest applying similar logic to prevent the problematic merge configuration.

The issue was resolved by tannerabread, who linked to pull request #41369, which includes the fix and additional safeguards for similar scenarios.

עדיפות/חומרה: עדיפות נמוכה / חומרה גבוהה

פלטפורמה: 3.5.0.beta8-dev עם Discourse Calendar (and Event) - 0.5 0162ed5

תיאור:

לאחר מיזוג נושאים ומחיקת פוסט ממוזג, הנושא המיועד הופך לבלתי נגיש עקב שגיאת שרת ([NoMethodError: undefined method 'category_id' for nil).

מצופה שהנושא יפעל כרגיל ולא יגרום לשגיאת שרת.

מעקב מלא
plugins/discourse-calendar/app/serializers/discourse_post_event/event_serializer.rb:137:in `category_id'
(eval at /home/discourse/.bundle/gems/ruby/3.3.0/gems/active_model_serializers-0.8.4/lib/active_model/serializer.rb:467):5:in `_fast_attributes'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:468:in `rescue in attributes'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:455:in `attributes'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:480:in `_serializable_hash'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:359:in `serializable_hash'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:347:in `as_json'
activesupport (7.2.2.1) lib/active_support/json/encoding.rb:23:in `encode'
activesupport (7.2.2.1) lib/active_support/json/encoding.rb:23:in `encode'
activesupport (7.2.2.1) lib/active_support/core_ext/object/json.rb:42:in `to_json'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:331:in `to_json'
multi_json (1.15.0) lib/multi_json/adapters/oj.rb:56:in `dump'
multi_json (1.15.0) lib/multi_json/adapters/oj.rb:56:in `dump'
multi_json (1.15.0) lib/multi_json/adapter.rb:25:in `dump'
multi_json (1.15.0) lib/multi_json.rb:139:in `dump'
app/controllers/topics_controller.rb:1383:in `block (2 levels) in perform_show_response'
actionpack (7.2.2.1) lib/action_controller/metal/mime_responds.rb:224:in `respond_to'
app/controllers/topics_controller.rb:1377:in `perform_show_response'
app/controllers/topics_controller.rb:191:in `show'
actionpack (7.2.2.1) lib/action_controller/metal/basic_implicit_render.rb:8:in `send_action'
actionpack (7.2.2.1) lib/abstract_controller/base.rb:226:in `process_action'
actionpack (7.2.2.1) lib/action_controller/metal/rendering.rb:193:in `process_action'
actionpack (7.2.2.1) lib/abstract_controller/callbacks.rb:261:in `block in process_action'
activesupport (7.2.2.1) lib/active_support/callbacks.rb:121:in `block in run_callbacks'
app/controllers/application_controller.rb:428:in `block in with_resolved_locale'
i18n (1.14.7) lib/i18n.rb:353:in `with_locale'
app/controllers/application_controller.rb:428:in `with_resolved_locale'
activesupport (7.2.2.1) lib/active_support/callbacks.rb:130:in `block in run_callbacks'
activesupport (7.2.2.1) lib/active_support/callbacks.rb:141:in `run_callbacks'
actionpack (7.2.2.1) lib/abstract_controller/callbacks.rb:260:in `process_action'
actionpack (7.2.2.1) lib/action_controller/metal/rescue.rb:27:in `process_action'
actionpack (7.2.2.1) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action'
activesupport (7.2.2.1) lib/active_support/notifications.rb:210:in `block in instrument'
activesupport (7.2.2.1) lib/active_support/notifications/instrumenter.rb:58:in `instrument'
activesupport (7.2.2.1) lib/active_support/notifications.rb:210:in `instrument'
actionpack (7.2.2.1) lib/action_controller/metal/instrumentation.rb:76:in `process_action'
actionpack (7.2.2.1) lib/action_controller/metal/params_wrapper.rb:259:in `process_action'
activerecord (7.2.2.1) lib/active_record/railties/controller_runtime.rb:39:in `process_action'
actionpack (7.2.2.1) lib/abstract_controller/base.rb:163:in `process'
actionview (7.2.2.1) lib/action_view/rendering.rb:40:in `process'
rack-mini-profiler (4.0.0) lib/mini_profiler/profiling_methods.rb:116:in `block in profile_method'
actionpack (7.2.2.1) lib/action_controller/metal.rb:252:in `dispatch'
actionpack (7.2.2.1) lib/action_controller/metal.rb:335:in `dispatch'
actionpack (7.2.2.1) lib/action_dispatch/routing/route_set.rb:67:in `dispatch'
actionpack (7.2.2.1) lib/action_dispatch/routing/route_set.rb:50:in `serve'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:53:in `block in serve'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:133:in `block in find_routes'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:126:in `each'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:126:in `find_routes'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:34:in `serve'
actionpack (7.2.2.1) lib/action_dispatch/routing/route_set.rb:896:in `call'
lib/middleware/omniauth_bypass_middleware.rb:35:in `call'
rack (2.2.17) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.17) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.17) lib/rack/head.rb:12:in `call'
actionpack (7.2.2.1) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/csp_script_nonce_injector.rb:12:in `call'
config/initializers/008-rack-cors.rb:14:in `call'
rack (2.2.17) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.17) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/cookies.rb:704:in `call'
activerecord (7.2.2.1) lib/active_record/migration.rb:674:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call'
activesupport (7.2.2.1) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (7.2.2.1) lib/action_dispatch/middleware/callbacks.rb:30:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/executor.rb:16:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call'
logster (2.20.1) lib/logster/middleware/reporter.rb:40:in `call'
lib/middleware/default_headers.rb:13:in `call'
railties (7.2.2.1) lib/rails/rack/logger.rb:41:in `call_app'
railties (7.2.2.1) lib/rails/rack/logger.rb:29:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/remote_ip.rb:96:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/request_id.rb:33:in `call'
rack (2.2.17) lib/rack/method_override.rb:24:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/executor.rb:16:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/static.rb:27:in `call'
rack (2.2.17) lib/rack/sendfile.rb:110:in `call'
lib/middleware/missing_avatars.rb:22:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/host_authorization.rb:143:in `call'
rack-mini-profiler (4.0.0) lib/mini_profiler.rb:334:in `call'
lib/middleware/processing_request.rb:12:in `call'
message_bus (4.4.1) lib/message_bus/rack/middleware.rb:60:in `call'
railties (7.2.2.1) lib/rails/engine.rb:535:in `call'
railties (7.2.2.1) lib/rails/railtie.rb:226:in `public_send'
railties (7.2.2.1) lib/rails/railtie.rb:226:in `method_missing'
rack (2.2.17) lib/rack/urlmap.rb:74:in `block in call'
rack (2.2.17) lib/rack/urlmap.rb:58:in `each'
rack (2.2.17) lib/rack/urlmap.rb:58:in `call'
unicorn (6.1.0) lib/unicorn/http_server.rb:634:in `process_client'
unicorn (6.1.0) lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn (6.1.0) lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn (6.1.0) lib/unicorn/http_server.rb:143:in `start'
unicorn (6.1.0) bin/unicorn:128:in `\u003ctop (required)\u003e'
bin/unicorn:96:in `load'
bin/unicorn:96:in `block in \u003cmain\u003e'
bin/unicorn:95:in `fork'
bin/unicorn:95:in `\u003cmain\u003e'

שלבי שחזור:

בגרסת 3.5.0.beta8-dev עם התוסף Discourse Calendar (and Event) - 0.5 0162ed5 מופעל:

  1. צור נושא חדש נושא 1 - שיימחק עם פוסט בודד על ידי משתמש1 שהוא tl1

  2. צור נושא חדש נושא 2 - שישבור עם פוסט בודד, ודא שאירוע לוח שנה הוא חלק מפוסט זה.

  3. בתור משתמש1 מחק את הפוסט שלך בנושא 1 - שיימחק כאשר הנושא נעול והפוסט שלך מוחלף ב"(נושא נמחק על ידי המחבר)"

  4. בתור משתמש2 בעל הרשאות מנהל:

  5. בחר פוסטים בנושא 1 - שיימחק ובחר את הפוסט הראשון (שכעת נמחק)

    .

  6. בתור משתמש2 מחק את הפוסט הראשון שמוזג זה עתה בנושא 2 - שישבור (הפוסט שקורא “(נושא נמחק על ידי המחבר)”) זה יגרום לנושא 2 - שישבור להישבר ולזרוק את השגיאה הנ

2 לייקים

המון תודה על הפירוט המפורט. מסכים שצריך לסדר את זה, בינתיים אני אשים על זה תגית pr-welcome.

לייק 1

תודה לשניכם על הדו"ח המפורט והמעקב. נתקלתי זה עתה בבעיה דומה לאחר מיזוג נושאים עם אירועי לוח שנה ולא הצלחתי להבין מדוע הנושא נשבר. שמח לראות שזה מתועד.

אשים עין על כל PR בנושא זה. בינתיים, מועיל לדעת שניתן להשבית את התוסף באופן זמני כפתרון עוקף. ספרו לי אם יש משהו שאוכל לעזור לבדוק.

למידע נוסף, אני חושב שאני יכול לפשט את השחזור:

  • אפשר את שניהם: Calendar enabled ו-Discourse post event enabled
  • כמנהל, צור Topic1
  • כמנהל, צור Topic2 וכלול אירוע פוסט באמצעות ‘צור אירוע’ מתפריט המלחין עם העיגול-עם-פלוס
  • כמנהל, עבור ל-Topic1 והשתמש במפתח הברגים של הנושא כדי לבחור את ה-OP ולמזג ל-Topic2 עם סימון ‘שמור על הסדר הכרונולוגי לאחר המיזוג’

בשלב זה, אירוע הפוסט כבר אינו ה-OP של הנושא עבור Topic2

  • כמנהל, מחק את Topic2 באמצעות מחיקת הפוסט של ה-OP או אפשרות מחיקת הנושא

תוצאה: borkity bork. הנושא שנמחק אינו נגיש. שגיאה ב-/logs של NoMethodError (undefined method ‘category_id’ for nil)


האם התיקון כאן יהיה למנוע את המיזוג שיחליף את האירוע כ-OP?

בעת ניסיון למזג פוסט אירוע (אחד שממוקם כראוי ב-OP) לנושא אחר, זה נחסם עם זה ביומנים:

נכשל בעיבוד תגובת חטיפה כראוי : ActiveRecord::RecordNotSaved : אירוע יכול להיות רק בפוסט הראשון של נושא

(שגיאת ה-UI כללית יותר, ‘אירעה שגיאה בהעברת פוסטים’, שיהיה נחמד אם היא הייתה מפורטת יותר)

האם ניתן ליישם משהו דומה כדי למנוע מיזוג שמוציא את האירוע ממצב ה-OP?

3 לייקים

This has been fixed + some additional guarding for other similar scenarios

לייק 1