بالنسبة لبعض المشاركات، يؤدي استدعاء PostRevisor إلى تعيين post_id إلى nil. هل أنا مجنون؟
الإجابة: لا. يصل PostRevisor إلى post.topic، وهو nil لمشاركة في موضوع محذوف. ثم يقوم بتعيين post.topic إلى nil، والذي بدوره يعين post.topic_id إلى nil.
أعتقد أنه يجب على PostRevisor الحصول على الموضوع على النحو التالي:
أنا أعمل على نص برمجي يقوم بإصلاح روابط goo.gl (الخدمة في طريقها إلى الإيقاف قريبًا، لذا يبحث النص البرمجي عن روابط goo.gl، ويجلب ما يتم إعادة توجيهها إليه ويستبدل عنوان URL الخاص بـ goo.gl بالعنوان الذي يتم توجيهه إليه. إنه يعمل في الغالب.
ولكن
بالنسبة لعدد من المشاركات، يبدو أن كل شيء يسير على ما يرام، ولكن بعد ذلك يفشل PostRevisor لأن post.acting_user هو nil. وبعد ذلك، في عملية الاسترداد الخاصة بي، يبدو أن topic_id هو nil، ولكن ليس post هو الذي يكون nil، لأنه لا يزال لديه post_number.
begin
puts "Revising (#{count}/#{total_posts}) https://mysite.com/t/#{post.topic_id}/#{post.post_number}"
puts "missing topic_id for post #{post.id}" if !post.topic_id
next if !post.topic_id
PostRevisor.new(post).revise!(system_user, raw: new_raw, **revision_options)
rescue => e
puts "cannot revise (number: #{count} https://tw.forumosa.com/t/#{post.topic_id}/#{post.post_number}): #{e}"
end
بالنسبة لغالبية المشاركات، يعمل هذا بشكل جيد، ولكن بالنسبة لمجموعة فرعية منها، فإنه يفشل على هذا النحو. وإذا قمت بتشغيل الكود يدويًا سطرًا بسطر، أحصل على نفس الشيء. يبدو الأمر، على الرغم من ذلك، أنه إذا قمت بتنفيذ pr=PostRevisor.new(post)، أرى أن المشاركة في سجل pr ليس لديها topic_id وبعد ذلك إذا قمت بفحص post، فإنها تحتوي الآن على topic_id معين إلى nil.
لأنه إذا كنت تقوم بتغيير 3000 منشور باستخدام gsub وتعبير نمطي معقد مع مجموعة من الحالات الطرفية (إصلاح: goo.gl، http://goo.gl، https://goo.gl، ولكن لا تلمس https://maps.app.goo.gl، أو https://map.goo.gl، وربما يتم تحديد معدل طلباتك بواسطة goo.gl، وهكذا) فقد ترغب في استعادة المنشور قبل أن تفسده تمامًا!
لقد كان من الرائع جدًا أن تكون قادرًا على النظر إلى التعديلات ورؤية قبل وبعد والقدرة على التراجع! سيؤدي أحد الإصدارات إلى تحويل https://maps.app.goo.gl/abd12 إلى شيء مثل https://maps.app.https://maps.google.com/;lkajw3rpoazse;flknmase;faijserfasefklasdfa، على سبيل المثال.
منذ سنوات كان هناك نص برمجي مشابه حاولت تشغيله لعميل ما، وقالوا (بكلماتي الخاصة، وليس كلماتهم) “يا رجل. هل تعتقد أننا سنقوم بتشغيل الكود الخاص بك الذي يغير عددًا لا يحصى من المنشورات بهذه الطريقة العشوائية ولا توجد طريقة للتراجع عنها؟ فكر مرة أخرى.”
Topic.find(post.topic_id)
ActiveRecord::RecordNotFound: Couldn't find Topic with 'id'=179227 [WHERE "topics"."deleted_at" IS NULL]
from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/finder_methods.rb:428:in `raise_record_not_found_exception!'
تم حذف الموضوع.
إذن، السؤال هو ما إذا كان من المفترض ألا تتمكن من مراجعة المشاركات في المواضيع المحذوفة.
أعتقد أنني لن أهتم وسأجعل النص البرمجي الخاص بي يتحقق من post.topic مقابل nil بدلاً من post.topic_id.
نعم، هناك نقص كبير في السلامة هنا مع المفتاح الخارجي!
أعتقد أن بعض الضوابط (آه) معطلة لأن الجداول كبيرة جدًا عادةً.
ربما قام شخص ما بإجراء topic.delete وليس destroy. يا إلهي.
كان بحثي عن المشاركات مثل Post.where("raw like '%goo.gl%'")، وهذا سيعيد المشاركات في مواضيع محذوفة. وبعد ذلك، تحتوي هذه المشاركات على topic_id، ولكن ليس موضوعًا. أعتقد أن هناك طريقة لجعل Topic.find يعيد المواضيع المحذوفة (لأن المسؤول يمكنه رؤية تلك المواضيع، وهذا هو سبب ارتباكي الشديد. هذه السلة الصغيرة سهلة الفقدان.)
لذا ربما كان يجب أن أفعل ذلك وأحدّث المشاركة قبل استدعاء PostRevisor؟
ولكن في تجربة المستخدم يمكنني تحديث مشاركة في موضوع محذوف، لذا أفكر أن
def initialize(post, topic = post.topic)
@post = post
@topic = topic
# Make sure we have only one Topic instance
post.topic = topic
end
يجب أن يكون
def initialize(post, topic = post.topic)
@post = post
@topic = topic || Topic.with_deleted.find_by(id: post_topic_id)
# Make sure we have only one Topic instance
post.topic = topic
end
سأقوم بنقل هذا إلى Bug في حال اعتقد شخص آخر أنه كذلك.
ولكن هذا يعمل:
if !post.topic # posts in delted topics have no topic and break PostRevisor
post.topic = Topic.with_deleted.find_by(id: post.topic_id)
next if !post.topic
end
PostRevisor.new(post).revise!(system_user, raw: new_raw, **revision_options)
كانت هناك مشاركات في 3 مواضيع تسببت في تعطل Rails. لقد استسلمت بشأن ذلك.