استرداد المواضيع بناءً على حقل مخصص؟

باستخدام الدليل المفيد جدًا الذي وضعه @angus، تمكّنت من إضافة حقول مخصصة إلى المواضيع والمجموعات.

بعد إضافة حقل مخصص بنجاح، هل توجد طريقة (فعّالة) لـ استرجاع العناصر بناءً على ذلك الحقل المخصص؟

على سبيل المثال، لنفترض أنني أضفت الحقل المخصص fun_level إلى المواضيع. إذن، أصبح لدينا الآن الحقل topic.fun_level (نص) الذي أُضيف عبر ملحقي.

الآن، أريد استرجاع وعرض قائمة بالمواضيع التي تحتوي على fun_level = "super-duper-fun".

كيف يمكنني فعل ذلك؟


إذا أردنا استرجاع جميع المواضيع ذات وسم معين، يمكننا استخدام ajax('/tags/tag-name.json').then(function(result))...، كما هو مُستخدم في هذا المنشور التوضيحي.

أما بالنسبة للحقل المخصص الذي أنشأناه للتو، فمن غير المتاح (أعتقد) استخدام هذه الطريقة. لأن ذلك سيتطلب إنشاء وحدة تحكم (controller) للحقل المخصص (مثل وحدة تحكم لـ fun_level، تحتوي على طريقة show تسترجع بطريقة ما جميع المواضيع التي يساوي فيها fun_level قيمة المعامل :fun_level، أو ما شابه ذلك).

أفترض أن هناك طريقة أكثر مباشرة؟

إعجاب واحد (1)

أعتقد أنني توصلت إلى طريقة واحدة لاسترجاع المواضيع بناءً على حقل مخصص: البحث عنها واسترجاع النتائج.

إليك مثال، تخيل أن لديك زرًا بإجراء “searchForTopics()” في مكان ما، وتحاول استرجاع المواضيع التي يحتوي حقلها المخصص fun_level على القيمة “super-duper-fun”:

(سيكون هذا الكود ضمن ملف JavaScript بصيغة ES.6، مثل ملف التهيئة):


import Topic from 'discourse/models/topic'; // ليس ضروريًا بناءً على الكود أدناه، لكنه ربما ذو صلة بإجراءات أخرى ذات صلة ترغب في تنفيذها
import { ajax } from 'discourse/lib/ajax';

export default {
    actions: {
        checkTopic(){
            let custom_field_value = 'super-duper-fun'
            let searchTerm = 'fun_level:' + custom_field_value
            let args = { q: searchTerm }
            ajax("/search", { data: args }).then(results => {
                let topics = results.topics
                topics.forEach(topic => {
                   // فقط للحصول على قائمة بأسماء المواضيع
                    console.log('topic name = ')
                    console.log(topic)
                })
            })
        }
    }
}

هذا يعمل. ولكن هل هذه هي الطريقة الأكثر كفاءة للقيام بذلك؟

على سبيل المثال، هل هذه الطريقة، التي تستخدم البحث، بنفس كفاءة الطريقة التي يستخدمها Discourse لعرض المواضيع المطابقة لوسم معين عند الانتقال إلى صفحة ذلك الوسم؟

إعجاب واحد (1)

الطريقة للقيام بذلك هي

  1. على جانب العميل: أضف معامل استعلام للموضوع باستخدام api.addDiscoveryQueryParam

  2. على جانب الخادم: قم بتصفية استعلامات الموضوع بناءً على المعامل باستخدام add_custom_filter في فئة TopicQuery (راجع lib/topic_query)

ستبدو استدعاءات التمرير (callback) الخاصة بـ add_custom_filter بهذا الشكل تقريبًا

::TopicQuery.add_custom_filter(:field_name) do |topics, query|
  if query.options[:field_name]
    topics.where("topics.id in (
      SELECT topic_id FROM topic_custom_fields
      WHERE (name = 'field_name')
      AND value = '#{query.options[:field_name]}'
    )")
  else
    topics
  end
end
3 إعجابات

تحرير: بعد التعمق أكثر في api.addDiscoveryQueryParam، أعتقد أنني فهمت الفكرة العامة الآن:

أريد استرجاع جميع المواضيع برمجياً التي تحتوي على الحقل المخصص fun_level = super-duper-fun. أظن أن طريقة في وحدة التحكم (controller) قد تنجز ذلك؟ (لا زلت أحاول فهم ذلك).

البديل هو إجراء بحث باستخدام ajax(“/search”) حيث أبحث في جميع المواضيع بناءً على الحقل المخصص fun_level=super-duper-fun. لكن إنشاء الحقل المخصص لا يكفي لتمكين ذلك. أحتاج إلى جعل الحقل المخصص fun_level أحد الحقول التي يمكن البحث فيها (تمامًا كما يمكنك البحث في فئات أو وسوم معينة)، وهذا لا يتم تلقائيًا.

بشكل ما، يُطلَب استخدام api.addDiscoveryQueryParam في ملف جافا سكريبت مع TopicQuery في ملف plugin.rb لتحقيق ذلك. لكن، بصراحة، لم أستطع جعلها تعمل بعد. لقد رأيت بعض الإضافات التي تستخدم هذه الطرق، لكنني لم أستطع فهم كيفية “إنجاز المهمة”. أعتقد أن هناك كودًا إضافيًا مطلوبًا، لكنني لم أعثر عليه بعد.

كيف تنتقل من هذه الطرق إلى جعل الحقل المخصص متاحًا فعليًا كمصطلح للبحث؟

رد سابق

شكرًا لك، @angus. للتوضيح، الهدف ليس أن يدخل المستخدمون قيم البحث يدويًا في مربع البحث. الهدف هو استرجاع المواضيع برمجياً بناءً على حقل مخصص معين. على سبيل المثال، سيذهب المستخدم إلى الصفحة /fun_levels/super-duper-fun ويحمل جميع المواضيع حيث يكون الحقل fun_level = ‘super-duper-fun’.

هل api.addDiscoveryQueryParam مخصص لهذا الغرض؟

عند النظر إلى أمثلة مثل هنا، لست متأكدًا من كيفية عمل addDiscoveryQueryParam لاسترجاع المواضيع فعليًا (لا أعتقد أن استدعاء هذه الطريقة يعيد نتائج يمكنني تحليلها).

ربما يكون الغرض منه السماح للمستخدم بالبحث يدويًا بالمصطلح في مربع البحث؟ هذا ليس الموقف الذي أسعى إليه. (قد يكون من الممكن أن أكون قد فاتني شيء ما).

لقد ذكرت استخدام ajax(“/search…”) سابقًا لأن هذا أفضل ما توصلت إليه حتى الآن لاسترجاع المواضيع، لكنني أتساءل عما إذا كانت هناك طريقة أكثر كفاءة للقيام بذلك، حتى لو تطلبت إعداد نموذج وطريقة في وحدة التحكم لعرض المواضيع تلقائيًا، مثل ما تفعله tags/:tag-name (هذا أكثر تعقيدًا، لذا آمل تجنبه، لكن إذا كانت هذه هي الطريقة الأفضل فسأعتبرها).

تعتمد أفضل نهج هنا على هدفك النهائي.

كيف تتخيل أن يعمل هذا؟ كخيار في الشريط الجانبي في /search؟

مرحبًا @angus. الهدف ليس إضافة استعلام في شريط البحث الجانبي (سيكون ذلك رائعًا، لكنه ليس الهدف هنا). الهدف هو تحميل المواضيع برمجيًا بناءً على حقل مخصص داخل قائمة مواضيع عندما يزور المستخدم صفحة معينة. أعتقد أنني فهمت جزء القالب/المكون (أي العرض). والآن أحاول فهم المنطق الذي سيحمل المواضيع.

سبب الحديث عن البحث هو تفكيري في أن تشغيل ajax("/search") مع custom_field=value عند زيارة الصفحة قد يكون طريقة نظيفة لتحميل المواضيع. لكنني فقط أحاول إيجاد الطريقة الأفضل التي تعمل.


تفاصيل أكثر:

في حالتي، الهدف الأول هو توجيه المستخدم إلى صفحة قالب جديدة أنشأتها في مسار جديد (/fun_levels/:fun_level)، وتحميل جميع المواضيع التي يكون فيها الحقل المخصص fun_level مطابقًا لـ :fun_level.

لقد فهمت بشكل منفصل كيفية إنشاء القالب وتحميله في المسار. الآن أريد تحميل المواضيع المطابقة برمجيًا داخل مكون قائمة المواضيع الموجود في الصفحة.

بشكل مثالي، أود تجنب إنشاء نموذج “fun_level” جديد (الذي لم أقم به بعد)، فقط للحفاظ على الأمور أكثر بساطة وسرعة في التنفيذ. لكنني منفتح على ذلك إذا كان ذلك سيؤدي حتمًا إلى أداء أفضل بكثير (هذه صفحة سيتم استخدامها كثيرًا).


سيكون من الجيد أيضًا معرفة كيفية إضافة القدرة على جعل “fun_level” خيارًا في شريط البحث الجانبي، حيث أتوقع أنني سأرغب في ذلك أيضًا. وربما تكون أفضل طريقة لتحميل المواضيع بناءً على الحقل المخصص هي إضافة الحقل المخصص إلى خيارات البحث، ثم استدعاء ajax("/search") مع الاستعلام الذي يكون “fun_level: super-duper-fun”.

لذا قد تكون الأمور المتعلقة بالبحث مهمة هنا. لكن المهمة الرئيسية الآن هي تحميل المواضيع في صفحة ما بناءً على حقل مخصص عندما يزور المستخدم تلك الصفحة.

هل يُقصد أن تكون هذه الصفحة التي تحتوي على قائمة المواضيع مشابهة لصفحات قوائم المواضيع الموجودة حاليًا في Discourse، أم أنها تختلف جوهريًا عنها؟

إعجابَين (2)

مختلف جوهريًا. لكن التركيز هنا هو فقط كيفية تحميل المواضيع التي تحتوي على قيمة حقل مخصص (مثل fun_level = ‘super-duper-fun’) إلى مكون {{topic-list topics=selectedTopics showPosters=true}} الذي أقوم بإدراجه في الصفحة.

عند التعامل مع قوائم المواضيع، يكون السؤال هو ما إذا كنت ستقوم بتوسيع بنية اكتشاف Discourse الحالية، أم أنك ستقوم بإنشاء بنية خاصة بك، مما يغير طريقة التنفيذ. هناك العديد من الأسئلة ذات الصلة بما تسعى إليه والتي نتجاوزها هنا.

لذلك، إذا لم تكن تقوم بتوسيع بنية الاكتشاف، فلن تقوم بالجزء الأول من ما اقترحته أعلاه. ومع ذلك، يجب أن تقوم بالجزء الثاني، وهو إضافة الفلتر المخصص إلى TopicQuery. ستحتاج أيضًا إلى مسار على جانب العميل مع استدعاء AJAX إلى نقطة نهاية مرتبطة بملف list_controller.rb. يمكنك العثور على مسارات وحدة تحكم القائمة في config/routes.rb عن طريق البحث عن list#.

يجب عليك استخدام نقطة نهاية قائمة المواضيع نفسها التي تستخدمها عملية اكتشاف Discourse، لأنك ستحصل عندئذٍ على أشياء مثل الترقيم (التي يتم التعامل معها عبر التحميل عند التمرير في مكون قائمة المواضيع)، والتعامل مع الأذونات، والعديد من الأشياء الأخرى جاهزة من الصندوق.

لذلك ستحتاج إلى:

  1. ملف plugin.rb يحتوي على الفلتر المخصص
  2. ملف المسار على جانب العميل
  3. قالب على جانب العميل
إعجاب واحد (1)

شكرًا لك على المعلومات.

أنا سعيد بأي طريقة تكون أسهل للحصول على المواضيع المطابقة لقيمة الحقل المخصص. لدي مسار/قالب يعمل حاليًا في /fun_levels/:fun_level، والذي يقوم بتحميل مكون {{topic-list}}. مرة أخرى، إذا كانت هذه الطريقة تعتمد على البحث عن قيمة الحقل المخصص (ajax(/search))، فهذا يعمل أيضًا. أعتقد بشكل متزايد أن هذه هي الطريقة الأكثر مباشرة. لقد لم أستطع جعلها تعمل بعد.

وللتوضيح، طريقتي الحالية هي:

  1. الحصول على المواضيع عبر ajax (أحتاج فقط إلى معرفة النقطة الطرفية الصحيحة/كيفية إعداد هذه النقطة الطرفية — وهذا هو المفتاح)،
  2. تحليل النتيجة، و
  3. تنفيذ component.set('showTopics', parsed-result) لتحميل المواضيع في {{topic-list topics=showTopics}}.

هذه الطريقة تبدو لي غامضة بعض الشيء. أرى الأساليب في list_controller، مثل def topics_by، ولكن كيف يمكنني أخذ أحد هذه الأساليب وتعديله لإرجاع مواضيع بناءً على قيمة حقل مخصص؟

أنصحك بعدم اتباع هذا الأسلوب لعدة أسباب. آسف لأنني غامض، لكن شرح السبب بالكامل سيستغرق وقتًا أطول مما أملكه حاليًا.

أسهل طريقة هي استخدام إحدى النقاط النهائية الموجودة في قائمة التحكم (list controller). فهي مُعدة بالفعل لتقديم قوائم المواضيع. يمكنك العثور عليها في routes.rb، ولكن باختصار، هي الفلاتر /latest، /top وما شابه. للحصول على قائمة مع فلتر مخصص، ستحتاج إلى استخدام معامل استعلام (query param) مثل هذا:

/latest?fun_level=5

باستخدام الفلتر المخصص. يمكنك تتبع فئة TopicQuery بدءًا من list_controller.rb لفهم كيفية عملها، على سبيل المثال، تقوم بإضافة فلترك المخصص كمعامل مدعوم للتحكم. السبب في شعورك بالغموض هو أن هذا المتحكم والفئة يتوليان معالجة العديد من الأشياء نيابةً عنك مثل الترقيم (pagination) والفلاتر المختلفة، والتي ستحتاج إلى إعدادها يدويًا إذا اتبعت طريقة أخرى.

الطريقة “الأخرى” التي ستعطي معنى (دون استخدام /search طبعًا)، هي إعداد متحكم خاص بك للمسار، يستخدم فئة TopicQuery تمامًا كما يفعل list_controller.rb. ستحتاج إلى إنشاء متحكم Rails إذا كنت تضيف مسارًا جديدًا تمامًا في أي حال، لذا فإن هذا نهج معقول آخر، رغم أنك ستحتاج إلى التعامل مع أشياء مثل الترقيم بنفسك. يجب أن تستخدم فلترًا مخصصًا إذا اتبعت هذا النهج.

أدرك أن بعض هذا قد يبدو غامضًا، ومع ذلك فأنت تتعامل مع وظائف معقدة هنا. لشرح هذا بالكامل، سأحتاج إلى كتابة دورة مكونة من 10 أجزاء. وهو ما قد أقوم به قريبًا في الواقع :slight_smile:

إعجابَين (2)

تحديث: أعتقد أنني نجحت (معظمها) في جعل الأمر يعمل (!). الآن، سيظهر هذا “أحدث” المواضيع المطابقة لقيمة الحقل المخصص. (كانت طريقة #latest هي الأقرب التي استطعت العثور عليها والتي تبدو منطقية في ملف config/routes.rb).

من المهم، في الواقع، تحميل جميع المواضيع التي تحتوي على قيمة الحقل المخصص fun_level ذات الصلة إلى الصفحة. هل هناك شيء آخر أحتاج إلى فعله لجعل ذلك يحدث؟


إليك الكود لملاحظاتي الخاصة، ولعلّه يكون مفيدًا للآخرين:

–لقد أنشأت الحقل المخصص :fun_level. ثم:

plugin.rb

TopicQuery.add_custom_filter(:fun_level) do |topics, query|
  if query.options[:fun_level]
    topics.where("topics.id in (
      SELECT topic_id FROM topic_custom_fields
      WHERE (name = 'fun_level')
      AND value = '#{query.options[:fun_level]}'
    )")
  else
    topics
  end
end

/connectors/my-plugin-outlet/fun-level.js.es6 (ملف جافا سكريبت يتم تفعيله عند الانتقال إلى الصفحة ذات الصلة. لذا يمكن وضع هذا الكود في ملف تهيئة أو في موصل يربط بمخرج إضافة. أنا أحب استخدام الكود الذي يرافق موصلًا، لذا سأستخدم مكون الإعداد هنا):

const ajax = require('discourse/lib/ajax')

export default {
    setupComponent(args, component) {
      let parsedResultArray = []
      var endPoint = '/latest?fun_level=' + funLevel  //funLevel = متغير يحتوي على القيمة من المعاملات   
      ajax(endPoint).then(function (result) {
            console.log('topic list result for topics matching that fun level = ')
            console.log(result.topic_list.topics)
            //حلل النتائج، وأضفها إلى parsedResultArray
            component.set('showTopics', parsedResultArray        
      })
   }
}

الآن، سيتم تحميل المواضيع إلى {{topic-list topics=showTopics}} الموجود في المكون المقابل، والذي تم وضعه في القالب عبر my-plugin-outlet.

هذه خطوة كبيرة إلى الأمام. شكرًا جزيلاً، @angus.

4 إعجابات

بفضل التعليمات المقدمة أعلاه (بفضل @angus و @JQ331)، تمكنت بنجاح من جلب المواضيع بالنظر إلى قيمة لحقل الموضوع المخصص عن طريق زيارة https://domain.com/latest?custom_field=custom_field_value

ومع ذلك، من تلك الصفحة، إذا نقرت على شعار الموقع (أو الزر الأحدث في الشريط العلوي)، فإنه يزيل معلمة الاستعلام (custom_field) من عنوان URL، ولكن تظل المواضيع مفلترة حسب custom_field.

عند التحديث، تعمل الصفحة كما هو متوقع (حيث تعرض جميع أحدث المواضيع).

كيف يمكنني إصلاح هذا السلوك؟

إعجاب واحد (1)