اذهب إلى المحتوى

محمد طاهر5

الأعضاء
  • المساهمات

    247
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    24

كل منشورات العضو محمد طاهر5

  1. وفقًا لتوثيق Laravel يجب عليك أن تضيف هذه الأسطر إلى resources/js/app.js، على فرض أنك تستخدم هذه المجلدات: import.meta.glob([ '../images/**', '../fonts/**', ]); الآن سيعالج Vite هذه الأصول الموجودة في هذه المجلدات عند تنفيذ الأمر npm run build، وستكون قادراً على استخدام Vite::asset للإشارة إلى الملفات الموجودة في هذه المجلدات داخل ملفات Blade. راجع الفقرة الخاصة بهذا الموضوع في التوثيق: https://laravel.com/docs/9.x/vite#working-with-blade-and-routes
  2. إنّ الهدف الرئيسي من عملية التسويق هي الحصول على المزيد من العملاء لمشروعك التجاري، ولكن من السهل أن ينسى المرء في خضمّ ذلك عملاءه الحاليين وأنّهم مهمّون أيضًا، وقد يكونون الأكثر أهمّية. أظهرت الدراسات أن احتمالية تحوّل العملاء الحاليين إلى المنتجات والخدمات الجديدة أكبر بمرتين من احتمالية تحوّل العملاء الجدد، وقد وجدت BI Intelligence أن نسبة تحوّل العملاء الجدد هي 2.4% مقارنة بـ 4.5% وهي نسبة تحوّل العملاء الحاليين. ولا يتعلّق الأمر بمعدلات التحويل فقط، فقد وُجد أنّ معدّلات اﻹضافة إلى سلّة المشتريات ترتفع بصورة ملحوظة وأنّ معدلات الارتداد bounce rate قد انخفضت كذلك بصورة ملحوظة بالنسبة للعملاء الحاليين، إذ يغادر 34.8% من العملاء الجدد دون إتمام عملية الشراء مقابل 24.4% من العملاء العائدين. صحيح أنّ هناك الكثير من العملاء الجدد الذين يمكن الحصول عليهم، ولكن ألا يستحقّ أولئك الذين أبدوا الاهتمام بمنتجك أو خدمتك أن يحصلوا على شيء من اهتمامك؟ أنت تمتلك أصلًا معلومات التواصل معهم بل وربّما معلومات أكثر تفصيلًا، مثل اﻷشياء التي قاموا بشرائها، والمدة التي استغرقوها في اتخاذ قرار الشراء، ومقدار المال الذي أنفقوه، وهل أثّرت قسائم التخفيضات على قرارهم في الشراء، و… الخ. هذا يعني أنّ معدّل تحويل العملاء الحاليين أفضل بكثير، إضافة إلى أنّك تمتلك جميع الأدوات اللازمة لتفتح أمامهم باب العودة إليك مرة أخرى بعد. يمكنك أن تقارن ذلك بما ستفعله للحصول على عملاء جدد والجهود التي ستبذلها للحصول على معلوماتهم اﻷساسية فقط. سأعرض عليك فيما يلي كيفية زيادة عمليات الارتقاء بالصفقة في متجرك الإلكتروني باستخدام التسويق بالبريد اﻹلكتروني. أضفِ على رسائلك الطابع الشخصي من الجيد أن ترسل إلى عملائك رسالة إلكترونية حول منتجاتك وخدماتك الجديدة (هذا الأسلوب يدعى بالبيع العابر Cross selling)، ولكن يمكن أن تقوم بما هو أكبر من ذلك، فبعد إتمام عملية البيع اﻷولى، تصبح لديك المعلومات الكافية حول عملائك لتقدّم إليهم المزيد من الاقتراحات المخصّصة والموجّهة إليهم. وتنطبق هذه النصيحة على بقية الأمور التي سنذكرها في هذه المقالة، إذ يجب عليك إضفاء الطابع الشخصي على أي استراتيجية ستعتمدها في التعامل مع العملاء، وينبغي عليك أن تُجري التعديلات المطلوبة في طريقة تواصلك مع عملائك (أو مع شريحة منهم على اﻷقل) وجعلها أكثر تخصيصًا. ويجعل هذا الأمر عملية تقسيم قوائم البريد اﻹلكتروني إلى شرائح مختلفة أمرًا في غاية الأهمية، ومع استحالة إضفاء الطابع الشخصي بالكامل في كل مرّة تتواصل فيها مع عملائك، فإن تقسيم قوائم البريد اﻹلكتروني ستساعدك في الوصول إلى مجموعات محدّدة في قاعدة عملائك. المصدر اعرض العناصر التي اشتراها العميل مؤخّرًا من أفضل اﻷمثلة على إضفاء الطابع الشخصي وتوطيد العلاقة التي تربطك بالعميل هو عرض المنتجات التي اشتراها العميل مؤخّرًا والحديث عنها. اسأل عملائك عمّا إذا كانوا راضين عن منتجاتك أو خدماتك، وإن كانوا كذلك فاطلب منهم أن يكتبوا آرائهم ومراجعاتهم، ولا تتردّد أبدًا في تذكيرهم بأنّ إنفاقهم لأموالهم وشرائهم لمنتجاتك يعني أنّهم قد وضعوا ثقتهم فيك وأنّ الأمر قد عاد بالفائدة عليهم، فلماذا لا يكرّرون هذا التجربة مرة أخرى؟ تعدّ عملية الشراء عملية عاطفية بالنسبة لأغلب الناس وعادة ما ترافق هذه العملية - سواء قبلها أو بعدها - الكثير من العوامل والمؤثّرات. ويمكن تحفيز هذه العوامل لدى العملاء عن طريق عرض المنتجات التي قاموا بشرائها مسبقًا، وبذلك يتذكّر العميل التجربة الإيجابية التي مرّ بها في السابق، وهنا تظهر أهمّية الدعم اللاحق لعملية الشراء والتسويق المخصّص. تقدّم Amazon مثالًا رائعًا في هذا الصدد، وهي تقوم بهذا الأمر في كل الأوقات، وأنا لا أقترح أن تبالغ في الأمر بشدّة (مع أنّ الأمر يأتي بفائدة كبيرة عليهم) ولكن يمكنك أن تبدأ بإرسال رسالة لاحقة بعد بضعة أيام من شراء العميل لأحد منتجاتك. بعد شراء جهاز Kindle Voyage، ترسل أمازون رسالة إلكترونية تعرض على العملاء حافظات خاصة بأجهزتهم الجديدة تساعد على حمايتها من الصدمات. احرص على إضافة بعض الصور الخاصة بالمنتج ليتمكن المتلقّي من ربط الرسالة بالموضوع. التوقيت المناسب من الصعب تقديم نصيحة محدّدة في هذا المجال لأنّ الأمر يعتمد كلّيًا على طبيعة مشروعك التجاري. يجب عليك أن ترسل رسالة البيع العابر أو الارتقاء بالصفقة عندما تشعر بأنّ العميل مستعدّ للشراء. والمقصود بالتوقيت المناسب هو الوقت المناسب من اليوم أو اليوم المناسب من الأسبوع، ولكن اﻷهمّ من ذلك أن تصل رسالتك عندما يكون العميل في مرحلة اتخاذ القرار. المصدر عليك أن تحرص أيضًا على أن لا تكون رسالتك مزعجة بالنسبة للمشتركين؛ لذا عليك الانتباه إلى موضوع التوقيت بصورة جيدة، والتخطيط لرحلة العميل من اللحظة التي تعرّف فيها على علامتك التجارية ﻷوّل مرّة وإلى حين إتمام عملية شراء منتجك أو خدمتك. يتوقّف أغلب المسوقين عند مرحلة الشراء على الرغم من أنّ ما يقارب 1 من كل 3 عملاء يشترون مرّة أخرى في السنة نفسها. تذكّر دائمًا مرحلة “الارتداد” التي تتبع نموذج قمع المبيعات التقليدي والتي قد تؤدّي إلى تنبيه العميل لاحتياجات جديدة. فعلى سبيل المثال، إن كنت تبيع الأجهزة اﻹلكترونية فيمكنك أن تقدّم إلى العملاء بعد شرائهم لأحد الأجهزة عروضًا لأهم الملحقات مثل حافظة للحاسب المحمول الجديد أو ملصق حماية الشاشة للهاتف الجديد. وإذا كنت مثلًا تبيع أحذية الركض فأنت تعرف أنّ عملائك يبدّلون أحذيتهم كل ستة أشهر تقريبًا؛ لذا سيؤدي إرسال الرسائل في هذه الفترات إلى زيادة ملحوظة في احتمالية شراء اﻷحذية من متجرك مرة أخرى. أما بالنسبة لأصحاب المتاجر اﻹلكترونية، فإنّ التوقيت المناسب يعتمد في العادة على تقديرات مستندة إلى دورة المبيعات وتدعمها بيانات الطلبات التي أجراها العملاء، ويمكنك أيضًا إيجاد طرق ذكية للاستفادة من البيع العابر بالاستناد إلى طريقة الاستخدام، كأن تقدم عرضًا في أسفل صندوق للمناديل أو ما شابه. إن كنت تستهدف عملائك بالاعتماد على طريقة الاستخدام، فقد أصبحت مطمئنًّا الآن إلى أنّك تستهدف العملاء في البقعة الحلوة Sweet Spot عندما يكونون بحاجة ماسّة إلى الحصول على المزيد من منتجاتك. كن طبيعيًا لا يرغب كثير من الناس في أن تباع لهم اﻷشياء، لذا حاول قدر الإمكان أن لا تبدو بمظهر البائع حين تتواصل معهم، وكلّما كنت طبيعيًا وعفويًا أكثر ازدادت فرص نجاحك. لا يحب الناس الشعور بأنّهم يتعرضون للخداع، وهذا هو السبب الذي يدفع الكثير منهم إلى عدم قراءة الرسائل اﻹلكترونية الترويجية أو النقر عليها. إن بدت رسالتك اﻹلكترونية كأي إعلان ترويجي آخر، فهناك احتمال كبير بأن يتجاهلها الناس؛ لذا احرص على أن تكون عروضك الترويجية ذات فائدة أكبر بالنسبة للعملاء لتقوية العلاقة التي تربطك بهم. إحدى الطرق الشائعة هي اقتراح ارتقاء في الصفقة من خلال رسالة في نظام خدمة العملاء تلي عملية الشراء مباشرة، مثل: الرسالة السابقة ودّية أكثر من هذه الرسالة: ثم اعرض بضاعتك لاحقًا في رسالة إلكترونية: وهكذا تكون قد قدّمت نصيحة إلى العميل بدلًا من محاولة بيعه سلعة ما، وكما ترى، فإن هذا اﻷسلوب أكثر لطافة وودّية، وأفضل مكان لاستخدام هذه العبارات هو إضافتها كملاحظة بسيطة في نهاية رسالة إلكترونية غير مخصّصة لبيع المنتجات. من الأساليب الرائجة أيضًا في هذا الصدد دمج المحتوى الخاص بالبيع العابر للمنتجات بمحتوى آخر، فمثلًا لو كنت ترسل إلى عملائك نشرة بريدية أسبوعية، يمكنك حينئذٍ الاستفادة من هذه الفرصة وإضافة بعض العروض إلى تلك النشرات البريدية. يمكنك أيضًا إنشاء نسخة خاصة من تلك النشرة اﻷسبوعية ترسلها إلى العملاء السابقين الذين اشتروا منتجات معيّنة. لنفرض أنّك تمتلك متجرًا للثياب الفاخرة على سبيل المثال، يمكنك أن ترسل بعض العروض الترويجية الخاصّة بمجموعة من الملحقات الفاخرة في حال اشترى العملاء إحدى الحقائب الجلدية، أما العملاء الذين اشتروا أحذية للأطفال فيتلقّون عروضًا ترويجية خاصّة بملابس اﻷطفال. لست مضطرًّا إلى تكرار اﻷمر برمّته، إذ يمكنك استخدام المحتوى ذاته لجميع القراء، ولكن انتقِ قسمًا واحدًا من ذلك المحتوى وغيّره بحسب الشريحة المستهدفة من العملاء. اطلب المساعدة قد تصبح الأمور متعبة إن كنت تقوم بها لوحدك؛ ولكن لماذا تتعب نفسك بهذه الطريقة عندما يكون بمقدورك طلب المساعدة من العملاء في تقديم المساعدة إليهم، وتأكد أن الكثير منّهم ستقبّل ذلك برحابة صدر. يمكن للتواصل مع العملاء لأجل الحصول على تغذيتهم الراجعة سيعود عليك بفائدتين هما: ستتمكن من تحسين الاقتراحات التي تعرضها عليهم عن طريق الاستفادة من المعلومات التي يقدّمونها إليك، وكلما كانت الاقتراحات أقرب إلى العملاء زادت معدّلات التحول وارتفعت المبيعات. ستعمل على توطيد علاقتك بالعملاء وذلك بمعرفة المزيد من المعلومات عنهم والاستفادة منها في عملك. إن كنت تقدّم للعملاء اقتراحات لمنتجات معيّنة بالاعتماد على تاريخ الشراء، فيجدر بك أن تتيح لهم فرصة الولوج إلى موقعك اﻹلكتروني والتصويت السلبي على بعض الاقتراحات التي يشعرون بأنّها غير ذات صلة برغباتهم واحتياجاتهم. وسيتاح لك بهذه الطريقة الحصول على مدخلات مباشرة وتحسين الاقتراحات التي تعرضها ليس فقط لهؤلاء العملاء بل لجميع العملاء الذي يمتلكون اهتمامات متشابهة. ليس المطلوب أن تكون الاقتراحات محدّدة أو تقنية للغاية. اطرح على القراء بعض اﻷسئلة المفتوحة مثل: “ما هو الأمور التي تفضّلها في الصيد؟” “باعتقادك ما هي الصيحات التي ستكون رائجة في الخريف القادم؟” “ما هو أكبر تحدٍّ تواجهه عندما تتعلم العزف على الغيتار؟” ستمنحك هذه اﻷسئلة بعض التصورات عن المشاكل التي يواجهها العملاء لتتمكّن من تقديم المنتج الأكثر ملائمة لهم. عادة ما تأتي هذه الأسئلة في مراحل مبكّرة من دورة الارتقاء بالصفقة أي قبل إرسال العروض الترويجية الحقيقية إلى القراء. روّج لمنتجاتك أعتقد أن هذه النقطة واضحة من عنوانها، ولكن عليك أن تحرص على تقديم بعض الاقتراحات أو العروض في مرحلة من ما من مراحل حملتك الترويجية. وأفضل طريقة للقيام بذلك في الغالب هي أن تربط العرض الجديد بإحدى المشتريات السابقة، وأن توضّح للعميل كيف أنّ العرض الجديد سيساعدك في تقديم قيمة إضافية إلى القيمة التي تلقّاها العميل عند شرائه للمنتج اﻷول. المصدر إليك بعض اﻷمثلة: هل حصلت على حاسوب محمول جديد؟ رائع! يمكنك إطالة عمر حاسوبك والحصول على المزيد من هذا الاستثمار مع لوحة التبريد هذه… هل أحببتِ حقيبة اليد التي اشتريتها الشهر الفائت؟ لدينا الأحذية التي تلائم تلك الحقيبة. تساعد هذه الطريقة في تسريع عملية اتخاذ القرار لدى العملاء، والمرور بالاحتياجات والوعي والاهتمامات والوصول إلى الرغبات مباشرة. أنت تعرف مسبقًا أنّ العملاء يحتاجون إلى اﻷشياء ويرغبون في الحصول عليها فهو السبب الذي دفعهم إلى شراء منتجك في المقام اﻷول. وها أنت الآن تخبرهم عن طريقة الحصول على المزيد من الأشياء التي سيحبّونها والتي ستساعدهم في حلّ مشاكلهم مهما كانت طبيعتها. ولكن ليس في وسعك القيام بالكثير. أنا لا أرغب في التقليل من شأن البيع العابر بصورة عامة، إذ أنّه لا يزال أسلوبًا فعّالًا للغاية عند استخدامه في البريد اﻹلكتروني، فإن اشترى العميل الكثير من الأحذية، ما عليك إلا أن ترسل إليه المزيد من العروض الخاصة بالأحذية، وسينجح الأمر. غاية ما في الأمر هو أن توصل للعميل وبأقصى سرعة ممكنة الفوائد التي سيجنيها من شراء المنتج الذي تروّج له، واستخدام صورة جيدة للمنتج، واستخدام دعوة قوية للإجراء. يمكنك الآن الارتقاء في صفقاتك إن لم تستخدم بعدُ أسلوب البيع العابر أو الارتقاء بالصفقة مع عملائك، فقد حان الوقت الآن للقيام بذلك (أفضل وقت لاتباع هذه اﻷساليب هو 5 دقائق بعد عملية البيع اﻷولى). وإن استخدمت هذه الأساليب مع عملائك فهذا أمر رائع. يمكنك الاستفادة من هذه النصائح لتضمن زيادة نسب التحويل. ترجمة - وبتصرّف - للمقال How to Increase E-commerce Upsells with E-mail Marketing لصاحبه Brian Barr. حقوق الصورة البارزة محفوظة لـ Freepik
  3. من منّا لا يعرف الرسائل المزعجة؟ على الرغم من أن البرامج والمرشحات المضادة للرسائل المزعجة تعمل على التقاط الكثير من هذه الرسائل؛ إلا أنّها لا زالت تشكّل ما يصل إلى 45% من الرسائل اﻹلكترونية بصورة عامّة وذلك حسب دراسة أجراها موقع SpamLaws.com. تأتي معظم الرسائل المزعجة من مصادر مشبوهة تحاول خداع المشتركين، ولكن في بعض اﻷحيان ترسل العلامات التجارية المشهورة عن طريق الخطأ رسائل لا تمرّ من خلال مرشّحات الرسائل المزعجة وينتهي بها المطاف في مجلد الرسائل المزعجة بدلًا من وصولها إلى صندوق البريد. وكمسوق، فمن المؤكّد أنّك ترغب في أن لا تصل رسائلك اﻹلكترونية إلى مجلد الرسائل المزعجة على اﻹطلاق، ولتضمن عدم حدوث ذلك أقدّم إليك فيما يلي ما يجب عليك معرفته حول الرسائل المزعجة. ما هي الرسائل المزعجة؟ يعرّف معظم الناس الرسائل المزعجة بأنّها رسائل تافهة وغير مفيدة، ومع أنّ هذا التعريف قد يبدو بسيطًا ولكنّه تعريف جيّد في الواقع. أما التعريف الأدقّ للرسائل المزعجة فهي الرسائل غير المرغوبة والتي لا تحتوي على مواضيع مهمّة بالنسبة إليك. عادة ما تُرسل الرسائل المزعجة بدفعات كبيرة على أمل أن يفتحها أحد ما، وفي بعض الأحيان ترسل شركة حقيقية هذا النوع من الرسائل أملًا في الحصول على بعض العمل، ولكن يُرسل بعض الأشخاص المشبوهين رسائل مزعجة بهدف اﻹيقاع بالناس وخداعهم، وبصرف النظر عن الهدف المبتغى من إرسال الرسالة فإن هذه الرسائل تُرسل دون إذن المستلم وتعدّ رسائل مزعجة. ومع هذا كله، فإنّ مجرمي الشابكة الذين يحاولون اﻹيقاع بالناس وخداعهم ليسوا هم المصدر الوحيد للرسائل المزعجة، فحتّى أكثر الشركات وثاقة قد ترسل في بعض اﻷحيان رسائل مزعجة دون أن تدرك ذلك. كيف تعمل المرشحات والبرامج المضادّة للرسائل المزعجة؟ تمسح المرشحات والبرامج المضادّة للرسائل المزعجة الرسائل اﻹلكترونية بحثًا عن رايات حمراء red flags، وتحدّد هذه الرايات بالاعتماد على بعض السمات العامّة التي تمتاز بها الرسائل المزعجة. تمسح المرشحات الرسائل اﻹلكترونية منذ إرسالها إلى حين وصولها لصندوق بريدك اﻹلكتروني وتحدّد المكان الذي ستستقرّ فيه الرسالة، فإمّا في صندوق الرسائل الواردة، أو في مجلد الرسائل المزعجة. عندما ترسل إليك جهة ما رسالة إلكترونية، فإنّ مزوّد خدمة اﻹنترنت (ISP) ومزوّد خدمة البريد اﻹلكتروني مثل Gmail أو Yahoo! يرسلان الرسالة عبر مرشحّات بُنيت في اﻷنظمة الخاصة بهما. وتأخذ هذه اﻷنظمة الكثير من اﻷمور في نظر الاعتبار مثل محتوى رسائلك اﻹلكترونية، وعدد الرسائل التي ترسلها، وما يسمى بسمعة الإرسال Sending reputation. تنظر المرشحات في أجزاء معيّنة من الرسالة اﻹلكترونية، مثل العنوان ومحتوى الرسالة اﻹلكترونية وحتى بيانات الترويسة والتي تعدّ بمثابة جهاز تحديد المواقع GPS بالنسبة للرسائل اﻹلكترونية حيث يتعقبّ مصدر الرسالة ووجهتها ووقت وصولها إلى وجهات متعددة. تبحث المرشحات ضمن هذه البيانات عن أيّ شيء خارج عن المألوف، وتصنّف الرسالة اﻹلكترونية كرسالة مزعجة إذا ما وجدت أي شيء مريب فيها. باﻹضافة إلى ما سبق، فهناك قائمة بمرسلي الرسائل المزعجة تدعى [بالقائمة السوداء]، وإذا ما اكتشف المرشح أنّ الرسالة اﻹلكترونية مرسلة من أحد الأطراف المدرجة في هذه القائمة فإنّه يمنع الرسالة من الوصول إلى صندوق البريد الوارد. تتفحص المرشحات محتوى الرسائل أيضًا، وتبحث عن العلامات التي يمكن أن توحي بأنّها رسالة مزعجة، كالعناوين المشبوهة، أو اكتظاظ المحتوى بالصور، أو وجود روابط مختصرة … الخ. إن لم تكن مطّلعًا على هذه الرايات الحمراء فمن المحتمل أن تحصل رسائلك على وسم الرسائل المزعجة دون أن تعي ذلك. التطور المستمر لمرسلي الرسائل المزعجة وللمرشحات مرسلو الرسائل المزعجة أذكياء، فهم يعرفون آلية عمل المرشحات ويطوّرون على الدوام أساليبهم لتجاوز هذه المرشحات وإيصال رسائلهم المزعجة إلى صندوق البريد الوارد. ولحسن الحظ، فإنّ المرشحات تتطوّر بنفس الوتيرة وكذلك اﻷمر بالنسبة لصناديق البريد اﻹلكتروني والتي أصبحت تقدّم المزيد من اﻷدوات التي تساعد أصحابها في التحكّم فيما يشاهدونه. وقد سهّلت الشركات المزوّدة لخدمة البريد اﻹلكتروني على المشتركين وسم الرسالة اﻹلكترونية بوسم الرسالة المزعجة، فلنفترض مثلًا أنّك تلقّيت رسالة تروّج لدواء يعالج نزلات البرد، ولم يكن لديك أدنى فكرة عن مصدر هذه الرسالة، فيمكنك حينها وسم تلك الرسالة بوسم الرسائل المزعجة وإرسالها إلى المجلد الخاص بهذا النوع من الرسائل. تتفحّص المرشحات الخاصة بصناديق البريد اﻹلكترونية الرسائل التي يسمها المشتركون حول العالم بوسم الرسالة المزعجة، وعن طريق إيجاد أوجه التشابه بين هذه الرسائل واستخدام المعلومات التي تقدّمها يمكن لهذه المرشحات أن تزداد قوة في مواجهة الرسائل المزعجة. وبمعنى آخر، فإنّ المشتركين يساعدون مرشحات الرسائل المزعجة في التفريق بين الرسائل المزعجة والرسائل العادية، وبالتالي في زيادة قوّتها. إنّه لمن الجيد معرفة أن مرشحات الرسائل المزعجة في تطور دائم، فهذا اﻷمر يجعل من الإنترنت مكانًا آمنًا بالنسبة للمستخدمين، ولكن لزيادة مقدار اﻷمان قدر المستطاع قد تلتقط هذه المرشحات بعض الرسائل التابعة لعلامتك التجارية، ولكن يمكنك تعلّم الطريقة الصحيحة ﻹرسال الرسائل والتي ستبعدك عن هذه المرشحات وعن مجلد الرسائل المزعجة. كيف ترسل رسائل إلكترونية أفضل وكيف تتجنب مرشحات الرسائل المزعجة؟ عادة ما يعاقب المشتركون المرسلين بأن يسموا الرسائل غير المتوقّعة في صندوق بريدهم اﻹلكتروني بوسم الرسائل المزعجة، وبمجرد أن تحصل رسالتك على هذا الوسم فإنّ سمعتك تصبح أسوأ وأسوأ بالنسبة لمرشحات الرسائل اﻹلكترونية؛ لذا عليك الابتعاد عن هذا الطريق فعواقبه وخيمة. ومن المؤكد أنّ السؤال التالي يدور في بالك الآن: كيف تتجنّب مرشّحات الرسائل المزعجة؟ إليك الطريقة التي تضمن لك أنّ رسائل حملتك البريدية لن تكون رسائل مزعجة. أرسل الرسائل إلى المشتركين المسجّلين في قائمتك البريدية فقط إنّ من القواعد الأساسية في التسويق بالبريد الإلكتروني هي إرسال الرسائل اﻹلكترونية إلى اﻷشخاص المشتركين طوعًا في القائمة البريدية، وهذا يعني أنّه لا يجوز شراء قائمة بريدية وإرسال الرسائل اﻹلكترونية إلى أشخاص لا يعرفونك ولا يعرفون منتجك. كذلك يجب عليك أن لا تفترض أنّ مجرد تبادل بطاقات العمل مع أحد اﻷشخاص في معرض تجاري مثلًا يعني رغبته في استقبال رسائلك اﻹلكترونية. لتتأكد من رغبة المشتركين في تلقّي رسائلك عليك أن تعتمد عملية اشتراك ذات خطوتين، فعندما يشترك أحد اﻷشخاص طوعًا في قائمتك البريدية عليك أن ترسل رسالة تأكيد إلى حسابه تطلب منه الموافقة على استقبال رسائلك اﻹلكترونية. رحّب بالمشتركين الجدد في أسرع وقت بعد أن ينضمّ مشترك جديد إلى قائمتك البريدية عليك أنت ترحّب به في أسرع وقت ممكن، فإن تأخرت قد ينسى المشترك بأنّه قد سجّل في السابق في قائمتك البريدية وسيسم رسائلك بوسم الرسائل المزعجة. ولتجنب ذلك عليك إرسال رسالة ترحيبية إلى المشتركين الجدد خلال الـ 24 ساعة الأولى، ولكنك لست مضطرًا إلى مراقبة قائمتك البريدية وإرسال الرسائل الترحيبية يدويًّا، بل يمكنك أتمتة هذه العملية وذلك بإنشاء رسالة ترحيب يتلقّاها جميع المشتركين وتُرسل إلى المشتركين الجدد في قائمتك البريدية. يجب أن تتضمّن الرسالة عبارات الترحيب وأن تعرّف المستخدم بك وبعلامتك التجارية، كما في المثال التالي من شركة Flight Center وهي شركة متخصّصة في حجوزات السفر. أضفِ على رسائلك طابعًا شخصيًا تبحث مرشّحات الرسائل المزعجة عن أي دليل يشير إلى معرفتك بالشخص الذي تراسله، ويمكنك القيام بذلك عن طريق إضفاء الطابع الشخصي على الرسالة اﻹلكترونية. يمكنك استخدام حقول الدمج ‘merge fields’ لإضافة اسم المشترك اﻷول إلى عنوان الرسالة أو إضافة وظيفة المشترك إلى متن الرسالة أو استخدام بيانات أخرى تابعة للمشترك بغية إضفاء المزيد من الطابع الشخصي على الرسالة. يؤدي إضفاء الطابع الشخصي على الرسائل اﻹلكترونية إلى نيل رضا المرشحات عن الرسالة إضافة إلى أنّ هذا اﻷسلوب يساهم في زيادة معدﻻت فتح الرسالة، فقد أظهرت الأبحاث ازدياد نسبة فتح الرسائل اﻹلكترونية ذات العناوين التي تمتاز بطابع شخصي بنسبة 26%. أرسل الرسائل اﻹلكترونية من النطاق التابع لشركتك يرسل المسوقون الجادّون رسائل إلكترونية من عناوين بريد إلكتروني تابعة لشركاتهم، وليس من الحسابات المجانية التي توفّرها خدمات مثل Gmail و Hotmail وغيرها. تبحث مرشحات الرسائل المزعجة عن المصداقية في الرسائلة اﻹلكترونية والرسائل التي تنتهي بالمقطع @gmail.com أو @hotmail.com لا تتوافق مع هذه المتطلبات. إضافة إلى ما سبق، احرص على أن يكون اسم المرسل معروفًا وذا سمعة حسنة، فرسالة إلكترونية من عنوان مثلSnowflake@ABCCompany.com لن توحي بالكثير من الثقة للمشترك. إليك مثالًا رائعًا من CoSchedule حيث اسم المرسل هو: “Breonna from CoSchedule.” وعندما يمرر المستخدم مؤشر الفأرة فوق الاسم في Gmail، يظهر عنوان البريد اﻹلكتروني إضافة إلى الصورة الخاصة بالمرسل. تجنّب استخدام الكلمات المزعجة تبحث مرشحات الرسائل المزعجة عن الكلمات المزعجة “buzz words” التي يستخدمها مرسلو هذا النوع من الرسائل بكثرة، وفيما يلي قائمة بأكثر الكلمات المزعجة استخدامًا بحسب Mequoda. هناك بعض الكلمات الواضحة التي يفضل مرسلو الرسائل المزعجة استخدامها بكثرة مثل “احصل على المزيد من المال” أو “مجّاني 100%” ولكن هناك بعض الكلمات التي قد تستخدمها العلامات التجارية المعروفة مثل “هدية مجانية” أو “اطلب اﻵن”. يجب عليك تجنّب استخدام هذه الكلمات قدر الإمكان في الرسائل التي ترسلها إلى قائمتك البريدية، ولكن إن كنت تقدّم هدية مجّانية فلا بد حينئذٍ من استخدام كلمات مثل “هدية مجّانية”؛ لذا إن كنت بحاجة إلى استخدام مثل هذه الكلمات فحاول إدخالها في السياق الصحيح، فعلى سبيل المثال: “سامر، يمكنك الحصول على هدية مجانية عند شرائك بمقدار 20$ من متجر الزمردة الزرقاء” وهكذا سيبدو عرضك مقبولًا. تجنب استخدام الروابط المختصرة عادة ما يختصر مرسلو الرسائل المزعجة الروابط لإخفاء أي دليل يكشف عن هويّتهم؛ لذا فإنّ وجود هذه الروابط في الرسالة يعدّ بالنسبة لمرشحات الرسائل المزعجة راية حمراء. وكمسوق فإنّه من الضروريّ جدًّا أن تكون مدركًا لهذا اﻷمر، ولربّما تكون قد تعوّدت على استخدام أدوات اختصار الروابط مثل Bitly ولكن يجب عليك تجنّب هذا اﻷمر في رسائلك اﻹلكترونية. استخدم مزوّد خدمة البريد اﻹلكتروني يمتلك خاصية اختبار الرسائل المزعجة تقدّم الكثير من مزوّدات خدمة البريد الإلكتروني اختبارات للرسائل المزعجة، وتمنح هذه الاختبارات المسوقين القدرة على تفحّص رسائلهم بواسطة مرشّح الرسائل المزعجة قبل إرسالها إلى المشتركين. ويمكن لمستخدمي Campaign Monitor على سبيل المثال إجراء اختبار الرسائل المزعجة والحصول على نصائح لتجنب هذا النوع من الرسائل: تقدّم هذه الخاصية طبقة حماية إضافية تمنع الرسائل اﻹلكترونية من الوصول إلى مجلد الرسائل المزعجة. الخلاصة صحيح أن الرسائل المزعجة هي مشكلة شائعة، ولكن آلية الكشف عن هذه الرسائل وكيفية إرسالها إلى المجلدات المخفية هو أمرٌ لا يدركه الكثيرون. يمكنك الآن وبالاستعانة بالمعلومات السابقة إنشاء حملتك التسويقية القادمة وكلّك ثقة بأنّك قد اتخذت جميع الإجراءات الاحترازية لضمان عدم وصول رسائلك اﻹلكترونية إلى مجلد الرسائل المزعجة. ترجمة - وبتصرّف - للمقال What’s Considered Email Spam and How to Avoid It لصاحبته Andrea Robbins. حقوق الصورة البارزة محفوظة لـ Freepik
  4. تعدّ النشرات البريدية اﻹلكترونية إحدى الوسائل المثالية للتواصل مع العملاء، فالناس يتصفحّون رسائلهم الإلكترونية في وسائل النقل أو أثناء تناول وجبات الطعام أو عند مشاهدة التلفاز. وعلى الرغم من أن التسويق بالبريد الإلكتروني يقدم عائدًا على الاستثمار (ROI) يقدّر بـ 44$ لكل دولار يُنفق على هذا التسويق، فإن صندوق البريد الشخصي يعدّ بيئة تنافسية، فبحسب دراسة أجرتها Emfluence فإنّ معدّل النقرات على الرسائل الموجّهة للأفراد (B2C) يصل إلى 4% في حين أن معدّل فتح هذه الرسائل يصل إلى 22%. كيف تتمكّن إذًا من حثّ الناس على اتخاذ الإجراء المطلوب عند استقبالهم لنشرتك البريدية؟ الإجابة هي عن طريق التصميم. إن لم تكن رسائلك الإلكترونية مصممّة بصورة جيّدة، فقد تحصل على نتائج مخيّبة للآمال. سنتحدّث في هذا المقال عن الطرق التي يمكنك اتّباعها لتحسن تصميم نشراتك البريدية ولتزيد بالتالي معدل النقرات عليها وتحصل على نتائج أفضل. تقليل الخيارات يزيد من فرصة اتخاذ اﻹجراء هل سمعت من قبل بالدراسة التي أجرتها Sheena Lyengar والمعروفة بدراسة المربى Jam Study؟ طُلب في هذه الدراسة من مجموعة من المتبضعين الاختيار من 24 نكهة مختلفةً من المربى، في حين طُلب من مجموعة أخرى الاختيار من بين 6 نكهات فقط. وكانت النتيجة مذهلة بحق، إذ كانت نسبة من اشترى المربى في المجموعة التي عُرض عليها 6 نكهات فقط هي 30%، أما المجموعة التي عُرض عليها 24 نكهة فقد كانت نسبة من اشترى المربى فيها هي 3% فقط. تبيّن هذه الدراسة أنّ الإنسان قد لا يتمكن من الاختيار في حال واجهته العديد من الخيارات، وعلى الرغم من أنّ الأمر قد يبدو مخالفًا للبديهة، إلا أنّ تقديم الكثير من الخيارات قد يكون أمرًا مربكًا للغاية. من الواضح أنّه يمكن تطبيق هذا المبدأ على تصميم النشرات البريدية لزيادة عدد النقرات، وأفضل طريقة للقيام بذلك هي تقليل عدد الخيارات المتاحة للمشتركين قدر اﻹمكان. ويمكن لهذا الأسلوب أن يأتي بنتائج إيجابية في الأنواع الأخرى من الرسائل اﻹلكترونية، سواء أكانت حملة تسويقية أو نشرة بريدية أسبوعية. وقد بينت دراسة أجرتها Ascend2 أنّ الدعوة إلى اﻹجراء Call to action التي تمتاز بكونها معبّرة وغير عامّة هي الوسيلة الأكثر فعالية لزيادة عدد النقرات. وهكذا، فإن تقليل عدد الخيارات التي تقدّمها إلى المشتركين سيزيد من عدد النقرات لا محالة، فلم لا تقدّم لهم إذًا خيارًا واحدًا بدلًا من ثلاثة خيارات؟ كيف تحسّن تصميم نشرتك البريدية استخدم قالبًا مختلفًا يمكن للقالب الذي تستخدمه في تصميم نشرتك البريدية أن يساعد في زيادة عدد النقرات، ولكنّك سرعان ما تصبح عرضة للاعتماد على نفس القوالب، فما إن تحصل على عدد من قوالب الرسائل الإلكترونية الفعّالة حتى تقع في فخ إرسال نفس النوع من الرسائل الإلكترونية مرارًا وتكرارًا، وهذا هو أحد الأسباب التي تؤدي إلى الحصول على معدّل نقرات مخيّبٍ للآمال، فقد سَئِمَ المشتركون من مشاهدة الرسالة الإلكترونية ذاتها مرة بعد أخرى. هناك تنسيق شائع للنشرات البريدية تعتمده معظم العلامات التجارية وعادة ما يكون بهذا الترتيب: يكون الإعلان أو المقالة المميزة في رأس النشرة البريدية. سطر أو سطران من النصوص الترويجية. رابط لندوة عبر الإنترنت، أو دورة تعليمية، أو ميزات منتج جديد.. الخ. مقالتان إضافيتان. يعدّ التسويق بالبريد الإلكتروني أحد أكثر الوسائل فعّالية في زيادة التفاعل مع العملاء وفي رفع نسب التحويل، ولكن الكثير من الشركات لا تستخدم هذه الوسيلة على الوجه الصحيح. أرسل الكثير من الرسائل الإلكترونية والقليل من المحتوى أجرى فريق Kayako عددًا من التعديلات على تصميم نشرتنا البريدية وحصلوا على بعض النتائج المثيرة للاهتمام. تضمّنت التعديلات الانتقال من رسالة إلكترونية نصف شهرية تحتوي على نصوص عادية إضافة إلى ثلاثة روابط لمواضيع مختلفة في المدونة، إلى رسالة أسبوعية ذات تصميم جذّاب، وأضفنا في التصميم الجديد رابطًا للمقالة التي نعتقد بأنّها ستكون محطّ اهتمام المشتركين في ذلك الأسبوع. لاحظ التعديلات التي أجريت على تصميم الرسالة: النصوص أصبحت قليلة جدًّا، فخير الكلام ما قلّ ودلّ. زر الدعوة إلى الإجراء بارز ويجذب الانتباه. مجموعة ألوان جذابة. صورة خاصة في الترويسة. أزرار وسائل التواصل الاجتماعي. اختيار واحد فقط للنقر عليه. وكانت نتائج هذه التعديلات صادمةً بحقّ، فقد تضاعف معدل النقرات في ذلك الشهر، حيث قدّرنا الزيادة بنسبة 97.03%، وكان هذا نجاحًا باهرًا. أجرِ اختبارات A/B على تصميم نشرتك البريدية ولكن ما هو المحتوى الذي يجب عليك استخدامه في حملتك التسويقية؟ يمكنك إجراء اختبارات A/B على حملتك البريدية لمعرفة المحتوى الذي يأتي بأفضل النتائج بدلًا من إرسال الرسائل وانتظار النتائج. وفي حالتنا هذه، كنّا نعرف مسبقًا بأنّ المشتركين يستجيبون لحملتنا البريدية الأسبوعية بصورة أفضل من الحملة نصف الشهرية، لأنّ النشرة الأسبوعية تتضمّن خيارًا واحدًا فقط بالنسبة للمحتوى. كانت الخطوة القادمة بالنسبة لنا هي معرفة مدى أهمية الاختيار في تحديد نسب النقر على الرسائل الإلكترونية. وبالاعتماد على النجاح الكبير الذي حقّقناه مسبقًا عن طريق تغيير تصميم النشرة البريدية، أجرينا اختبارًا على تصميمين مختلفين هما: النسخة A: مقالة مميزة، وثلاثة روابط داعمة. النسخة B: مقالة مميزة فقط. لقد افترضنا أنّه للحصول على المزيد من النقرات لكل رسالة إلكترونية؛ يجب علينا أن نضيف ثلاثة روابط لمقالات إضافية في حال لم تنل المقالة المميزة التي اخترناها استحسان القارئ. هذه هي النسخة A من التصميم: توجد في النسخة B مقالة مميزة واحدة فقط ولا وجود لأي روابط أخرى: امتدّ الاختبار لثمانية أسابيع باستخدام بيانات Kayako، وكانت النتيجة أنّ النسخة A كانت أفضل بقليل من النسخة B، حيث حصلت على 13 نقرة إضافية. لم يكن المشتركون ينقرون على الروابط الإضافية، ولكن وجودها لم يشكل عائقًا في وجه القراء ولم يدفعهم إلى عدم النقر على أي شيء بتاتًا. لهذا فقد استنتجنا أن إتاحة عددٍ من الخيارات قد لا يكون أمرًا مثبّطًا بالضرورة ولكن يجب توخي الحذر في هذا الجانب، ومن الضروري جدًّا أن تكون الرسائل الإلكترونية معبّرة وأن تُرسل بصورة منتظمة. يجب أن يتيح البرنامج الذي تستخدمه للتسويق بالبريد الإلكتروني إجراء اختبارات A/B لحملتك التسويقية، وعادة ما تُجرى هذه الاختبارات بإرسال كلّ نسخة إلى شريحة مختلفة من المشتركين في القائمة البريدية. اجعل المحتوى في غاية التركيز والوضوح تميل الرسائل الإلكترونية الموجّهة للشركات (B2B) إلى اتباع التنسيق ذاته، وغالبًا ما تفشل في جذب انتباه القراء، في حين أنّه يجب على الرسائل الإلكترونية الموجّهة للأفراد أن تكون ذات جودة عالية جدًّا لتحصل على فرصة للوصول إلى صندوق بريد المشتركين، فالمنافسة على جذب انتباه الجمهور أشدّ ضراوة بكثير. إن إرسال الكثير من الرسائل الإلكترونية يعني أنّ هناك الكثير من الخيارات؛ لذا حاول أن تتجنب الوقوع في هذه المشكلة بجعل المحتوى الذي ترسله في رسائلك التسويقية في غاية التركيز والوضوح، فلا تربك قرّاءك مثلًا بتقديم جميع المقالات التي نشرتها في الشهر الفائت. أخبر المشتركين عن موضوع رسالتك الإلكترونية في عنوان الرسالة (لا تبالغ في ذلك) والتزم بذلك الموضوع في متن الرسالة. تذكّر أنّ معظم القرّاء سيطالعون رسالتك الإلكترونية باستخدام هواتفهم الذكية، وأن التركيز على هذه الشاشات الصغيرة أمرٌ صعبٌ للغاية، ولا تنس كذلك أنّ أغلب القراء مستعجلون؛ لهذا يجب أن يدفعك كل ذلك إلى اختصار رسائلك الإلكترونية التسويقية وجعلها مركّزة ومنظّمة وسريعة. ختامًا إنّ الهدف من زيادة عدد النقرات في الرسائل الإلكترونية هو محاولة تحسين نسب التحويل والحصول على المزيد من المبيعات في نهاية المطاف. وبطبيعة الحال يجب أن يساهم كل جزء من المحتوى الذي تقدّمه إلى القرّاء في تحقيق هذا الهدف الاستراتيجي وأن ينال اهتمام المشتركين واستحسانهم على الدوام. قد تظنّ بأنّ تقديم أكبر قدر ممكن من المحتوى في الرسائل الإلكترونية سيؤدي إلى تحفيز المشتركين للنقر على رسائلك الإلكترونية، ولكنّ تقديم الكثير من الخيارات قد يكون في الواقع سببًا لتثبيط المشتركين ودفعهم إلى الامتناع عن النقر. اجعل تصميم نشرتك البريدية بسيطًا وأجرِ اختبارات A/B على أشكال مختلفة من المحتوى، ثم راقب النتائج. ترجمة - وبتصرّف - للمقال How to Update Your Email Newsletter Design to Increase Clicks لصاحبه Adam Rogers. حقوق الصورة البارزة محفوظة لـ Freepik
  5. يتطلّب جذب العملاء إلى علامتك التجارية تقديم المحتوى الملائم قدر الإمكان، وسواء أكان المحتوى المقدّم عبارة عن رسالة إلكترونية، أو منشور في وسائل التواصل الاجتماعي أو حتى ورقة مطبوعة، فعليك أن تحرص على إضفاء الطابع الشخصي على ذلك المحتوى. تقدّم الرسائل الإلكترونية ذات الطابع الشخصي 6 أضعاف ما تقدّمه الرسائل الإلكترونية العادية من العائدات، وقد لاحظ المسوّقون زيادة في العائدات تقدّر بـ 760% في حملات التسويق المجزّئة. هذا يعني أن إضفاء الطابع الشخصي يأتي بنتائج ممتازة، وأنّ عليك اتباع هذا الأسلوب بصورة واسعة في رحلة التعامل مع عملائك. نعم رحلة! لو فكّرت في الأمر قليلًا سترى بأنّ كلّ عميل من عملائك في رحلة، ففي البداية سمع العميل عنك في مكان ما - ربّما في فيسبوك أو في إعلان تجاري أو في مدوّنة - فأصبحت مألوفًا بالنسبة إليه، بعدها بادر إلى التسجيل في قائمتك البريدية واشترى أحد منتجاتك وأصبح بذلك أحد عملائك. لكل عميل رحلة فريدة وخاصّة به، وهو الأمر الذي يجعل من أسلوب تخصيص المحتوى وإضفاء الطابع الشخصي عليه أسلوبًا مهمًّا للغاية. وسنتحدّث في هذا المقال عن كيفية الاستفادة من هذا الأسلوب خلال الرحلة التي يقطعها العميل معك بغية إرسال رسائل ملائمة وذات طابع شخصي، لتكون النتيجة في النهاية الحصول على أكبر مقدار ممكن من العائدات على الاستثمار عن طريق حملات التسويق بالبريد الإلكتروني. استخلص المعلومات عند انضمام المشتركين إلى قائمتك البريدية يستخدم المسوقون في العادة معلومات الشراء السابقة لإضفاء الطابع الشخصي على الرسائل التي يرسلونها إلى المشتركين، ولكن يجدر بك البدء باتباع هذا اﻷسلوب في أسرع وقت ممكن. يمكن استخلاص المعلومات التي يقدّمها من يبادر إلى التسجيل في قائمتك البريدية، ويمكن الاستفادة من هذه المعلومات لإضفاء الطابع الشخصي على المحتوى الذي ستقدّمه إليه. فعلى سبيل المثال، يطلب موقع Topshop عند التسجيل في القائمة البريدية إضافة الاسم وتاريخ الميلاد واسم الدولة، وتحديد ما إذا كان الشخص طالبًا أو لا. تقدّم Topshop باستخدام هذه المعلومات محتوًى ذا طابع شخصي وعلى نطاق واسع، وتحرص Topshop على تلقّي كل مشترك في القائمة البريدية على رسالة عيد ميلاد مخصّصة أو رسائل إلكترونية حسب الموقع الجغرافي. جمع المعلومات ليس مقتصرًا على نماذج التسجيل وحسب، بل يمكن استخدام عنوان IP الخاص بالمشترك للحصول على معلومات حول موقعه الجغرافي، وبهذا يمكن إرسال رسائل ذات طابع شخصي تقدّم عروضًا مرتبطة بالموقع الجغرافي للمشترك. قدم الاقتراحات بناءً على المشتريات السابقة وأسلوب التصفح ما الذي يحدث عندما يتّخذ المشترك اجراءات معيّنة في موقعك الإلكتروني؟ يمكن أتمتة عملية إرسال الرسائل الإلكترونية حسب الإجراء trigger-based الذي يتّخذه المشترك في الموقع الإلكتروني. بهذه الطريقة، يمكن تهيئة مجموعة من الرسائل الإلكترونية لضمان حصول كل مشترك على رسائل مرتبطة بالإجراءات التي اتّخذها، وذات طابع شخصي في نفس الوقت. فمثلًا، لو قضيت بعض الوقت في استعراض الصفحات المرتبطة بكراسي غرف الطعام على موقع Room & Board، فإنّك ستتلقّى ولمدّة ثلاثين يومًا رسائل إلكترونية ترويجية عن الكراسي تتضمّن مراجعات إيجابية. زامن العروض الرقمية مع سلوك العملاء في المتجر الحقيقي يكثر الحديث عن الجهود التي يجب عليك أن تبذلها في التسويق الرقمي، ولكن من النادر أن تجد من يذكر شيئًا عن مزامنة هذه الجهود مع ما يجري في المتجر الحقيقي. ومع ذلك، فإن الوقت المثالي لتسجيل العملاء في القائمة البريدية هو في الغالب عندما يكونون في المتجر الحقيقي. يمكنك استخدام المعلومات التي تحصل عليها في المتجر لإرسال رسائل إلكترونية مؤتمتة تتمتّع بطابع شخصي. فعلى سبيل المثال، إن تبنّيت قطّة ضمن إحدى فعاليات التبنّي التي تقيمها PetSmart سيُطلب منك التسجيل في برنامج جوائز PetPerks والذي يخوّلك الحصول على عروض ترويجية خاصّة، وبعد التسجيل ستحصل على رسالة إلكترونية مؤتمتة من PetSmart يشكرونك فيها على الشراء من متجرهم. ادع المشتركين إلى متجرك حسب موقعهم الجغرافي إنّ الاستفادة من الموقع الجغرافي للعميل هي من أفضل الوسائل التي يمكن استغلالها لإضفاء الطابع الشخصي على الرسائل المرسلة إليه، وبهذه الطريقة يمكنك دعوة العميل إلى زيارة متجرك وباستخدام الرسائل الإلكترونية المؤتمتة فقط. يتلقّى المشتركون في Kate Spade New York رسائل إلكترونية تتضمّن معلومات حول المتاجر القريبة منهم، ويمكن تبديل هذه المعلومات بصورة تلقائية بالاعتماد على الموقع الجغرافي للمشترك، فلو كنت تعيش في بوسطن Boston مثلًا، ستدعوك الرسالة إلى زيارة المتجر القائم في Newbury Street. أرسل تحديثات مؤتمتة إن كنت تمتلك معلومات عن المشتركين فيمكنك الاستفادة منها في إرسال تحديثات مؤتمتة تطلعهم فيها على المستجدّات وتذكّرهم بالعودة إلى متجرك والشراء مرة أخرى. يبعث Sephora وهو متجر متخصّص في أدوات التجميل تحديثات مؤتمتة للمشتركين من فئة VIB لإطلاعهم على آخر المستجدات. تتمتّع الرسائل الإلكترونية بطابع شخصي وتعرض النقاط التي حصل عليها المشترك، ومقدار المال اللازم إنفاقه للبقاء ضمن الفئة الحالية. اسأل المشتركين عن رأيهم في أدائك إنَّ طلب التغذية الراجعة من العملاء هو جزء من أجزاء الرحلة التي يقطعونها معك. كيف كانت تجربة العميل؟ وهل سينصح أصدقائه وزملائه بالتعامل معك؟ يمكنك إنشاء استبيانات مؤتمتة يتلقّاها المشترك بعد إكماله لحدث معين، فعلى سبيل المثال ترسل Oak Tree Mazda استبيان صافي نقاط الترويج NPS وذلك بعد أن يأخذ العميل سيارته إلى ورشة الصيانة التابعة لهم. الخلاصة التسويق المؤتمت هو أفضل وسيلة لتحسين تجربة العملاء، إذ يمكن إرسال المحتوى للشخص المناسب في الوقت المناسب، وبإضفاء طابع شخصي على ذلك المحتوى ستضمن أنّه ملائم للعميل قدر الإمكان. ترجمة - وبتصرّف - للمقال How to Incorporate Personalization Into the Customer Journey for Massive Relevance لصاحبته Samantha Ferguson. حقوق الصورة البارزة محفوظة لـ Freepik
  6. قد تصبح عملية التسويق لخدمتك أو مشروعك التجاري عملية مكلفة، وبالرغم من أن ذلك استثمار سيعود عليك بنتائج ممتازة على المدى الطويل، إلا أن الحصول على التمويل اللازم لتغطية التكاليف أمرٌ لا يخلو من الصعوبة، خصوصًا في الأيام الأولى من عمر الشركة. تحتاج معظم عمليات التسويق إلى ميزانية متوسطة على الأقل، ولكن هناك بعض الطرق الفعّالة التي يمكنك اتّباعها في الترويج لمشروعك التجاري دون أن يكلِّفك ذلك شيئًا على الإطلاق؛ إذ يمكن الاستعانة بقوة وسائل التواصل الاجتماعي في الترويج لخدمتك أو مشروعك التجاري، وفي تثقيف الناس حول ما تقدّمه والطريقة التي يمكنك مساعدتهم بها، وكلّ ذلك بالمجّان. لنلقِ نظرة على أفضل طرق التسويق للخدمات والمشاريع التجارية عبر وسائل التواصل الاجتماعي والتي لا تكلّف درهمًا واحدًا. 1. اشترك في Twitter Chats تعدّ محادثات تويتر (Twitter Chats) وسيلة ممتازة لجمع الأفراد المهتمّين بموضوع أو صنعة أو شركة معيّنة. ولما كان الجميع مرتبطين بوسم (hastag) معين فيمكن حينئذٍ استخدام محادثات تويتر لجذب عملاء جدد من الجمهور المستهدف. بصورة عامة، يبدأ المدير أو قائد الشركة بمحادثة في تويتر وذلك بتغريد سؤال واحد أو أكثر وتتضمن هذه التغريدات وسمًا خاصًّا بها، ويمكن للمشتركين الإجابة عن هذه الأسئلة باستخدام الوسم نفسه، وهكذا تكون جميع التغريدات ذات الصلة مرتبطةً بعضها ببعض. يمكن للمشتركين تقديم أفكارهم الخاصة، وعرض آراء متباينة، والتفاعل مع بعضهم البعض، وعادة ما تُنظَّم محادثات تويتر في الوقت نفسه كل أسبوع وتُطرَح مواضيع جديدة للنقاش في كل مرة. تخضع كل محادثة إلى قواعد وقوانين خاصة يضعها مُنشئ تلك المحادثة، ولكن ترويج المنتجات والخدمات بصورة مباشرة أمرٌ غير محبّذٍ على اﻹطلاق. ومع هذا، تشجع محادثات تويتر على إجراء المحاورات بين الأعضاء المهتمين بمواضيع متشابهة، لذا ستزداد فرصك في التواصل مع بعض الأشخاص من الجمهور المستهدف. يمكنك مثلًا إضافة روابط للمحتوى أو المنتج أو الخدمة التي تقدمها والتي تمثّل في نظرك حلًّا للمشاكل التي يواجهونها وذلك بعد إجراء محادثة بسيطة معهم في البداية. احرص فقط أن تكون المحادثة عفوية وطبيعية قدر الإمكان. تتنوع المواضيح المطروحة في محادثات تويتر تنوّعًا كبيرًا، وعليك أن تعرف المواضيع الملائمة لعملك. حاول التواصل مع بعض الروّاد في مجال عملك لتتعرّف عن طريقهم على بعض المحادثات المعروفة، وتابع على الدوام الأوسمة المرتبطة بمجال عملك، مع التذكير بأنّك قادر على إنشاء محادثة خاصّة بك. تذكّر عند المشاركة في المحادثات بأنّها تتحرّك وتتغير بسرعة؛ لذا حافظ على تركيزك وحاول التواصل مع أكبر قدر ممكن من الأشخاص، حتى لو لم تكن متأكّدًا من كونّهم جزءًا من جمهورك المستهدف. 2. كن نشطًا في مجموعات فيسبوك مجموعات فيسبوك هي طريقة أخرى لجمع الأشخاص المهتمّين بموضوع أو فكرة أو صنعة معيّنة عبر وسائل التواصل الاجتماعي. ولكن، على العكس من محادثات تويتر، فإن مجموعات فيسبوك تكون دائمية، ويمكن للأشخاص الانضمام إلى هذه المجموعات والخروج منها حسب رغبتهم، ويمكنهم كذلك ترك الرسائل وإضافة التعليقات وطرح الأسئلة في أي وقت يشاؤون. يمكن تشبيه مجموعات فيسبوك بالمنتديات، حيث هناك مدراء للمجموعات يضعون القواعد التي من شأنها تنظيم المجموعة وضمان التزام جميع أعضاءها بمواضعيها العامة، ويمكن للأعضاء إنشاء المحادثات وطرح الأسئلة والإجابة على المنشورات بكل حرية. تعتمد القواعد المفروضة في المجموعة - كما هو الحال في محادثات تويتر - على مؤسّسي المجموعة ومديريها، ولكن ليس من المحبّذ بصورة عامّة الترويج لمشروعك التجاري بصورة مباشرة في أيِّ مكان. يتطلب الترويج الفعال لمشروعك التجاري عبر مجموعات فيسبوك الحضور الدائم والفعّال، ومشاركة المحتوى الذي يقدّم حلولًا للمشاكل التي يواجهها أعضاء المجموعة وإجاباتٍ مفيدة للأسئلة التي يطرحونها. في بعض الأحيان تُطرح أسئلة معينة وبصورة متكرّرة في المجموعة دون أن يتمكّن أحدٌ من اﻹجابة عنها، وفي هذه الحالة عليك أن تستغلّ الفرصة وتُجري الأبحاث اللازمة لتقدّم محتوىً جديدًا يملأ هذه الفجوة. يمكن العثور على مجموعات فيسبوك - كما هو الحال مع محادثات تويتر - عن طريق البحث بالكلمات المفتاحية المرتبطة بمجال عملك، أو التركيز على الأماكن التي يتواجد فيها جمهورك المستهدف. احرص على أن تكون فعّالًا بعد الانضمام إلى المجموعة، إذ كلّما تعرّف أعضاء المجموعة عليك وعلى علامتك التجارية بصورة أكبر، ازدادت فرصة زيارتهم لموقعك الإلكترونيّ وربّما شراء منتجاتك. 3. تبنّى المحادثات ثنائية الأطراف تستخدم معظم المشاريع التجارية الصغيرة منصّات التواصل الاجتماعي لإرسال روابط للمحتوى والموقع الإلكتروني والمنتجات والخدمات التي تقدّمها. ولكن عادة ما يتجاهل الناس هذه الروابط عندما تُرسل في السياق الخاطئ، ومع أنّ الكثير من العملاء المحتملين إضافة إلى الجمهور المستهدف يرغبون في التفاعل والتواصل مع علاماتهم التجارية المفضّلة، فقد يؤدي أسلوب التواصل هذا والذي يكون من طرف واحد فقط إلى نفور هؤلاء الأشخاص وقد تكون النتائج سلبية. من الضرورة بمكان إدراك الطريقة الفعّالة لترويج الخدمات والمحتوى الذي تقدّمه على صفحات التواصل الاجتماعي، فالبدء بالمحادثة من الأمور المهمّة لجذب الانتباه إليك، ولا تتوقع أبدًا أن تحوز اهتمام المجتمع حينما لا تكون منتبهًا إلى السياق العام عند إرسال الروابط الخاصّة بك، وبطبيعة الحال فإن عدم حصولك على اهتمام الناس يعني أنّهم لن يتوجّهوا إلى موقعك اﻹلكتروني لشراء منتجاتك. هذا لا يعني عدم استخدام الروابط في وسائل التواصل الاجتماعي على الإطلاق، ولكن يجب عليك الانتباه إلى عدم الإلحاح في هذه المسألة، فالروابط وسيلة مهمّة لإيصال جمهورك المستهدف إلى موقعك الإلكتروني للتواصل معك أو لشراء المنتجات التي تقدّمها، ولكن عليك أن تحرص على استخدام الروابط في الجزء المناسب من المحادثة لتحفّز القرّاء على الاستجابة أو لتُطْلِعَهم على المزيد من المعلومات. الهدف الرئيسي هنا هو أن تكون المحادثة ثنائية الأطراف، ما يعني أنّ عليك أن تكون الطرف الفعّال في المحادثة، وإن استجاب أحد الأشخاص لمنشوراتك فعليك أن تردّ عليه من غير إبطاء لكي لا تتوقف المحادثة عند هذا الحدّ. أنصت دائمًا لما يطلبه جمهورك المستهدف، وقدّم إليهم المحتوى أو المعلومات أو المنتجات أو الخدمات التي تساعدهم في تحقيق طلباتهم وحلّ مشاكلهم. 4. تواصل مع الأشخاص المؤثرين يجب أن لا يقتصر التواصل على العملاء المحتملين فقط، فإلى جانب الجمهور المستهدف يجب عليك الاستفادة من منصّات التواصل الاجتماعي في التواصل مع الأشخاص المؤثّرين في مجال عملك، والمقصود بالأشخاص المؤثُرين هم الصحفيون والمدونون والروّاد في مجال عملك، بل وحتّى العلامات التجارية الأخرى التي لا تكون مُنافسةً لك بصورة مباشرة. يمكن أن لا يكون الأشخاص المؤثرون من عملائك، ولكنّهم يمتلكون على الأرجح قاعدة جماهيرية عريضة تضمّ جزءًا كبيرًا من الجمهور المستهدف والذي يمتلك ثقة كبيرة في اختيارات هؤلاء المؤثرين وفي آرائهم. إن تمكّنت من التواصل مع الأشخاص المؤثرين وكسب صداقتهم، فسيتعرّف عليك العديد من الأشخاص الجدد حينئذ وقد يفكّر هؤلاء في أن يصبحوا عملائك في المستقبل. يكفيك مثلًا أن يذكرك أحد الأشخاص المؤثرين في صفحته أو أن يعيد نشر إحدى منشوراتك وستحصل على عدد من العملاء الجدد لعلامتك التجارية. يمكنك بناء مثل هذه العلاقات بالتحاور مع أحد الأشخاص المؤثرين في مجال عملك، ويمكنك مثلًا الرد على منشوراتهم، أو مشاركة المحتوى الذي يقدّمونه لمتابعيهم، أو التواصل معهم عبر محادثات تويتر أو مجموعات فيسبوك، وسيساعد ذلك على توطيد العلاقة التي تربطك بهم وبنفس الطريقة التي تتبعها في حياتك الشخصية، وكلما ازداد التواصل أصبحت العلاقة أقوى وأقوى. احرص كذلك على أن تكون علاقتك بالأشخاص المؤثّرين علاقةً متبادلةً، بمعنى أن تشارك أنت أيضًا ما يقدّمونه من محتوى مع متابعيك، وأن توضّح لهم مدى قدرتك على مساعدتهم في تحقيق أهدافهم. الخلاصة يرتبط نجاح مشروعك التجاري ارتباطًا وثيقًا باتّباع الأسلوب الملائم في التسويق، غير أن هذا لا يعني أنّك بحاجة إلى إنفاق أموال طائلة لجذب العملاء المحتملين. إن كنت غير قادرٍ على إنفاق الكثير من المال أو كنت تبحث عن طريقة لتوفيره، فيمكنك الاستفادة من وسائل التواصل الاجتماعي في الترويج لخدماتك ومنتجاتك وبصورة فعّالة دون أن تنفق قرشًا واحدًا. لنراجع معًا الوسائل الأربعة التي يمكنك اﻻستفادة منها في الترويج لخدمات مشروعك التجاري عبر وسائل التواصل الاجتماعي وبالمجان: شارك في محادثات تويتر لتتواصل مع أفراد جدد في الجمهور المستهدف. كن نشطًا في مجموعات فيسبوك لتقديم الأفكار القيمة والمفيدة. ابدأ محادثات ثنائية الأطراف، وشارك المحتوى المفيد عندما يحتاج الجمهور المستهدف ذلك. احرص على تكوين علاقات مع الصحفيين والمدوّنين والرواد في مجال عملك. ما هي الوسيلة التي ستتبعها الآن من هذه الوسائل الأربعة المجانية؟ أخبرنا بذلك في التعليقات. ترجمة - وبتصرّف - للمقال 4 Free Ways to Find Clients Using Social Media Marketing لصاحبه Tom Ewer. حقوق الصورة البارزة محفوظة لـ Freepik
  7. اكتشفت مؤخرًا المتعة الكبيرة في استخدام مكتبة [Fractal المقدّمة من PHP League] لإنشاء استجابات للواجهات البرمجية التي تعطي مخرجات من نوع JSON وذلك عند العمل على نماذج Eloquent في إطاري العمل Laravel و Lumen للحصول على المخرجات التي أرغب بها. هذه الحزمة مشابهة إلى حدٍّ كبير لمكتبة ActiveModel Serializer في إطار العمل Rails، إذ إنّها تتيح لك التحكّم الدقيق بالمخرجات التي ترغب في وصولها إلى المستخدم، إضافة إلى أنّها تفصل الشيفرة المسؤولة عن إنشاء كائن JSON عن نموذج Eloquent وهذا أمر في غاية الأهمية. والآن بعد أن أتيح لي تطوير عدد من الواجهات البرمجية لفترة زمنية لا بأس بها، خطر لي أن أتحدّث عن الطرق التي اتبعتها في ربط Fractal مع تطبيقات Laravel و Lumen (تختلف طريقة الربط في إطار Lumen لأنّه لا يدعم ماكروات Response). المُسَلسِلات المخصّصة Costum Serializers بادئ ذي بدء، تدعم Fractal عددًا من المُسَلسِلات Serializers لتكوين بنية خاصة بالاستجابة، وتستخدم بصورة افتراضية المسَلسِل الذي يدعى بـ DataArraySerializer والذي يضيف مفتاح جذر root key يحمل الاسم data إلى الاستجابة، لذا إن كنت لا تمانع من استخدام هذا المُسَلسِل فيمكنك تجاوز هذه الخطوة. أما لو كنت ترغب في استخدام مُسَلسِل آخر فعليك تسجيل الصنف Manager مع حاوية IoC في مزوّد الخدمة AppServiceProvider أو في مزوّد خدمة آخر إن كنت ترى أنّه يناسبك أكثر، ولكن عليك الانتباه إلى أنّ دعم JSON-API غير مكتمل حتى الآن (المقالة الأصلية نشرت سنة 2015. (المترجم)). public function register() { $this->app->bind('League\Fractal\Manager', function($app) { $manager = new \League\Fractal\Manager; // Use the serializer of your choice. $manager->setSerializer(new \App\Http\Serializers\RootSerializer); return $manager; }); } إنشاء المحوّلات Transformers بعد ذلك سنحتاج إلى إنشاء بعض المحوّلات - محوّل لكل نوع من أنواع نماذج Eloquent التي ترغب في تخريجها بواسطة الواجهة البرمجية - وفي مثالنا هذا سأستخدم مدوّنة حيث يضمّ النموذج AppUser عددًا من نماذج AppPost وسنعرض المستخدم مع المقالات الخاصّة به. أنشأت مجلّدً للتحويلات داخل مجلّد Http: app/Http/Transoformers، والآن يمكنني إنشاء محوّلين، الأول لنموذج User والثاني لنموذج Post. محوّل المستخدمين User سيكون سهلًا، إذ أنّه سيُرجع الحقول المطلوبة من قبل واجهتي البرمجية. في هذا المثال، يمتلك النموذج User خاصّية is_admin وهي عبارة عن قيمة منطقية boolean. ويمكنني التعبير عن ذلك في المحوّل بواسطة العبارة (bool) $user->is_admin ولكن اعتبارًا من الإصدار 5.0 وما بعده من Laravel أصبح بالإمكان استخدام خاصّية $casts في النموذج وسيكون Eloquent قادرًا بعدها على معالجة عملية الوصف بالنيابة عنك. يستحسن معالجة مثل هذه الأمور ضمن النموذج لأنّها ستكون متاحة في التطبيق برمّته. <?php namespace App\Http\Transformers; use App\User; use League\Fractal\TransformerAbstract; class UserTransformer extends TransformerAbstract { /** * Turn this item object into a generic array. * * @param \App\User $user * @return array */ public function transform(User $user) { return [ 'id' => $user->id, 'first_name' => $user->first_name, 'last_name' => $user->last_name, 'email' => $user->email, 'is_admin' => $user->is_admin, 'created_at' => $post->created_at->toDateTimeString(), 'updated_at' => $post->updated_at->toDateTimeString() ]; } } بما أنّ خصائص التاريخ في نماذج Eloquent هي نسخ من مكتبة Carbon يمكن إذًا استخدام الدوال المساعدة التي تقدّمها هذه المكتبة لإرجاع التاريخ بالصيغة التي نرغب بها. وفي مثالنا سنستخدم الدالة toDateTimeString() وسيكون التاريخ بالصيغة التالية: Y-m-d H:i:s (السنة - الشهر - اليوم الساعة:الدقائق:الثواني). والآن سنحتاج إلى محوّل لأجل نموذج Post، وسيكون هذا المحوّل مختلفًا عن السابق لأنّنا نرغب في تضمين النموذج User المرتبط بنموذج Post مع هذه الاستجابة. <?php namespace App\Http\Transforers; use App\Post; use League\Fractal\TransformerAbstract; class PostTransformer extends TransformerAbstract { /** * List of resources possible to include * * @var array */ protected $availableIncludes = ['user']; /** * List of resources to automatically include. * * @var array */ protected $defaultIncludes = ['user']; /** * Turn this item object into a generic array. * * @param \App\Post $post * @return array */ public function transform(Post $post) { return [ 'id' => $post->id, 'title' => $post->title, 'content' => $post->content, 'created_at' => $post->created_at->toDateTimeString(), 'updated_at' => $post->updated_at->toDateTimeString(), 'published_at' => $post->published_at->toDateTimeString() ]; } /** * Include user. * * @param \App\Post $post * @return League\Fractal\ItemResource */ public function includeLevels(Post $post) { return $this->item($post->user, new UserTransformer); } } لاحظ أنّه بالإمكان إرجاع $this->collection داخل المحوّل إن كنت ترغب في ربط مجموعة بدل من عنصر واحد. إنشاء الاستجابات في Laravel عادة ما أنشئ مزوّد خدمة Fractal FractalServiceProvider والذي يضمّ التابع register() الذي قمت بوصفه سابقًا، ثم أسجّل بعض الماكروات في التابع boot() كما تلاحظ هنا. سيؤدي ذلك إلى إضافة تابعين إضافيين إلى معمل (factory) Response في Laravel وسيسهّل إرجاع الاستجابات على هيئة عناصر أو مجموعات. لاحظ أنّي حدّدت نوع (type hint) المحوّل ليكون نسخة من الصنف TransformerAbstract وذلك لأنّي أنشئ دائمًا المحوّلات من الاستجابات بدلًا من صيغة الدالة المغلقة closure لأنّي أرى بأنّ هذه الطريقة ستحافظ على ترتيب الشيفرات التي أكتبها. لكن إن كنت تفضل استخدام الدوال المغلقة بدلًا من المحوّلات فيمكنك بكل ساطة أن لا تحدد نوع المحوّل ضمن المعاملات. public function boot() { $fractal = $this->app->make('League\Fractal\Manager'); response()->macro('item', function ($item, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) use ($fractal) { $resource = new \League\Fractal\Resource\Item($item, $transformer); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); }); response()->macro('collection', function ($collection, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) use ($fractal) { $resource = new \League\Fractal\Resource\Collection($collection, $transformer); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); }); } والآن أصبح من السهل إنشاء استجابة واحدة (لمستخدم واحد مثلًا) ومجموعة من الاستجابات (لجميع مقالات المدوّنة مثلًا). /** * GET /users/1 * * @param int $userId * @return \Illuminate\Http\Response */ public function showUser($userId) { $user = \App\User::findOrFail($userId); return response()->item($user, new \App\Http\Transformers\UserTransformer); } /** * GET /posts * * @return \Illuminate\Http\Response */ public function showPosts() { $posts = \App\Post::with('user')->get(); return response()->collection($posts, new \App\Http\Transformers\PostTransformer); } إن كنت ترغب في استخدام حالة استجابة HTTP أخرى مثل 201 (تم الإنشاء) أو 204 (لا يوجد محتوى) يمكنك وبكل سهولة تمرير رمز الحالة كمعامل ثالث إلى الماكرو. إنشاء الاستجابات في Lumen يتطلّب إنشاء الاستجابات في Lumen اتباع أسلوب مختلف قليلًا؛ ذلك لأنّ Lumen لا يدعم الماكروات في معمل Response؛ لذا سأضيف هذه التوابع إلى المتحكّم الرئيسي في الواجهة البرمجية. /** * Create the response for an item. * * @param mixed $item * @param \League\Fractal\TransformerAbstract $transformer * @param int $status * @param array $headers * @return Response */ protected function buildItemResponse($item, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) { $resource = new \League\Fractal\Resource\Item($item, $transformer); return $this->buildResourceResponse($resource, $status, $headers); } /** * Create the response for a collection. * * @param mixed $collection * @param \League\Fractal\TransformerAbstract $transformer * @param int $status * @param array $headers * @return Response */ protected function buildCollectionResponse($collection, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) { $resource = new \League\Fractal\Resource\Collection($collection, $transformer); return $this->buildResourceResponse($resource, $status, $headers); } /** * Create the response for a resource. * * @param \League\Fractal\Resource\ResourceAbstract $resource * @param int $status * @param array $headers * @return Response */ protected function buildResourceResponse(\League\Fractal\Resource\ResourceAbstract $resource, $status = 200, array $headers = []) { $fractal = app('League\Fractal\Manager'); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); } يمكنك الآن استدعاء أي تابع من هذه التوابع في أي متحكّم موروث من هذا المتحكّم لإنشاء نفس الاستجابات التي أنشأناها مع Laravel. return $this->buildItemResponse($user, new \App\Http\Transformers\UserTransformer); return $this->buildCollectionResponse($posts, new \App\Http\Transformers\PostTransformer); ترجمة - وبتصرّف - للمقال Using Fractal with Laravel and Lumen لصاحبه Dwight Conrad Watson.
  8. من المؤكّد أنّك ترغب في زيادة وعي الجمهور بمشروعك التجاري، وتدفعك هذه الرغبة إلى زيادة التركيز على أدوات التسويق. وهناك اعتقاد سائد بأنّ برمجيات ومنصّات التسويق تلائم الشركات الكبيرة حصرًا، ولكن الواقع عكس ذلك تمامًا. وبصرف النظر عن طبيعة مشروعك التجاري أو سنوات الخبرة التي تتمتع بها، فإن خير وسيلة لمواكبة السوق الذي يمتاز بالتغير الدائم هي الاستفادة من أدوات التسويق المختلفة ضمن خطتك التسويقية، لتضمن بهذه الطريقة انتشار علامتك التجارية بين شريحة أكبر من الناس، وجذب العملاء والشركاء، وغير ذلك الكثير. ولمساعدتك في هذه المهمّة سنقدّم في هذا المقال نبذةً مختصرةً حول سبع أدوات فعّالة يمكنك الاستفادة منها لتحقيق أهدافك. بعض الإحصائيات المرتبطة بأتمتة التسويق يقرّ 91% من المسوّقين أن وجود أداة تسمح للفريق بتحليل بيانات التسويق والعملاء ومراجعتها والعمل عليها بصورة مستمرة يعدّ إضافة قيّمة إلى مشروعهم التجاري. تساهم منصّات أتمتة التسويق في زيادة إنتاجية المبيعات بنسبة 14.5% وتخفيض نفقات التسويق العامة بنسبة 12.2%. حظيت المشاريع التجارية التي تعتمد على أتمتة التسويق في زيادة العملاء المحتملين، بنسبة زيادة في العملاء المهتمّين Qualified leads وصلت إلى 451%. اكتشف تقرير صدر عام 2015 أن 51% من الشركات تستخدم 21 أو أكثر من الحلول الرقمية التسويقية. إن العامل الأكثر أهمّية في اختيار منصّة أتمتة التسويق بالنسبة لـ 86% من المسوّقين هو سهولة الاستخدام. 43% من الشركات تستخدم منصّات أتمتة التسويق منذ أربع سنوات على الأقل. يستخدم معظم المسوّقين والشركات أدوات أتمتة التسويق أو أنهم يخطّطون للقيام بذلك، وإن كنت لا تستخدم هذه المنصّات فقد حان الوقت للقيام بذلك لتتمكّن من اللحاق بمنافسيك بل والتغلّب عليهم. ولكن ما هي الأدوات التي يمكنك استخدامها؟ فيما يلي سنستعرض سبعة أدوات ممتازة. 1. Infusionsoft تمتلك Infusionsoft أكثر من 125,000 مستخدم وخبرة تصل إلى 16 عامًا في هذا المجال. وقد أثبتت المنصّة فعّاليتها الكبيرة وذلك بسبب سعرها المعقول والأداة الرائعة لإنشاء الحملات. وما أعجبني في هذه الأداة هو أنّها أتاحت الفرصة أمامي وأمام أعضاء الشركة لإنشاء حملات بالصورة التي كنّا نفكر بها، وهذه الميزة ستفتح أمامك الأبواب على مصراعيها، إذ يمكنك إنشاء الحملة بالصورة التي تخيّلتها تمامًا. إضافة إلى ذلك تتوفر في Infusionsoft ميزات مثل الاقتباسات المؤتمتة، ونقاط العملاء المحتملين، والأوسمة غير المحدودة وغير ذلك الكثير. إن كنت تبحث عن أداة تجمع بين مُنشِئ حملات مثالي وبين السعر المنخفض، فهذه المنصّة هي الخيار الأفضل. 2. Ontraport ﻻ تتحلّى Ontraport بشهرة المنصّات المعروفة في مجال أتمتة التسويق، ومع ذلك فهذه الأداة عمليّة للغاية، فمثلًا يمكن إعداد الدفعات الدوريّة في هذه الأداة بكل سهولة وهذا أمر مفيد جدًّا، أضف إلى أنّ التدريب الأولي على هذه الأداة مجّاني. أداة إنشاء التسلسل Sequence builder في هذه المنصّة جيّدة جدًّا وترتبط بصورة رائع مع WordPress، Facebook و Google AdWords. وجود مثل هذه التسهيلات أمر ضروريّ للغاية عند التعامل مع منصّات أتمتة التسويق، وهذا ما توفّره منصّة Ontraport. جدير بالذكر كذلك أنّ هذه المنصّة تنتمي إلى مجموعة المنصّات منخفضة التكاليف، وهو من الأمور المهمّة في اختيار أدوات الأتمتة. 3. Marketo قد لا تكون Marketo أداة منخفضة التكاليف، ولكنّها تستحقّ ما يدفع من أجلها، وتعمل بصورة مثالية مع المنصّات منخفضة التكاليف. ولقد استفدنا كثيرًا من Marketo في تحديد مدى تأثير كل خطّة من الخطط المعتمدة من قبلنا على العائدات الإجمالية. تسعى جميع الشركات الاجتماعية Social enterprise للوصول إلى أكبر قدر ممكن من الناس والتطور بصورة مستمرة، ولكن من الضرورة بمكان معرفة مدى فاعلية الاستراتيجية المتبّعة لتحقيق ذلك. وقد استخدمنا التحليلات المفصّلة التي تقدّمها Marketo - إضافة إلى أمور أخرى - في تشخيص نقاط الضعف والقوة هذه الاستراتيجيات. إلى جانب ذلك تقدّم هذه المنصّة دليلًا يعنى بأتمتة التسويق، وقد ساعدت هذه الميزة أعضاء فريقنا من الذين لم يكونوا على دراية كافية بهذا الموضوع على التعلّم بسرعة كبيرة، الأمر الذي وفّر علينا الكثير من الوقت. 4. Assignment Helper مع أنّ Assignment Helper ليست أداة لأتمتة التسويق ولكنّها تساوي باقي الأدوات في الأهمية، فالجودة العالية للمحتوى من الأمور الضرورية جدًّا لجذب الزوّار والتأكد من عودتهم مرة أخرى؛ لهذا يجب توفير محتوى عمليٍّ غنيٍّ بالمعلومات وبأسلوب متميّز. في بعض الأحيان لا يتوفّر الوقت الكافي للكتابة، أو ينقطع الإلهام أو ربّما لا تمتلك المهارة اللازمة للكتابة، وحلّ هذه المشاكل يتمثّل في التعامل مع خدمات الكتابة الاحترافية، وأرى أن خدمة Assignmet Helper يمكن الاعتماد عليها في هذا الصدد. تقدّم بعض خدمات الكتابة وعودًا بتوفير محتوى عالي الجودة، ولكنّها ﻻ تفي بهذه الوعود في أغلب الأحيان، ولكن هذه الأداة على النقيض تمامًا، إذ يتم إرسال المحتوى في الموعد المحدّد، وخدمة العملاء متاحة في كل وقت، وبهذا يمكن لشركتنا الاجتماعية أن تركّز على مشاريع أخرى أكثر أهميّة. 5. Customer.io لا يمكن أن نعدّ Customer.io منصّة عادية لأتمتة التسويق، فهي تمتاز بواجهة استخدام خفيفة وسريعة، ودعم عملاء مخصّص، وتركّز في المقام الأول على التسويق بالبريد الإلكتروني. وبدلًا من إرسال الرسائل اﻹلكترونية بناء على مشاهدات الصفحة، ترسل Customer.io الرسائل الإلكترونية بناء على الأحداث، وهذه الميزة مفيدة للغاية. تقدّم المنصّة كذلك معلومات تفصيليّة يمكن الاستفادة منها في إنشاء حملات تسويقية تؤدّي إلى تحقيق المزيد من النجاحات. تقدّم هذه المنصّة أيضًا ميزة مفيدة أخرى، وهي إمكانية متابعة أداء كل رسالة إلكترونية تم إرسالها على حدة، وتتيح هذه الميزة القدرة على تعديل حملة التسويق والتأكّد من أن الناس سيفتحون ويقرؤون الرسائل أو النشرات البريدية التي يتلقّّونها. 6. HubSpot تؤدّي HubSpot القليل من كل شيء، وهي واحدة من أفضل أدوات أتمتة التسويق بالنسبة للمشاريع التجارية الصغيرة. هذه المنصّة مفيدة جدًّا عندما ترغب في الشروع بأتمتة التسويق وتكون بحاجة إلى أدوات بسيطة وعملية في نفس الوقت. لقد استخدمت شركتنا هذه الأداة وكانت تجربة رائعة بالفعل، فقد ساعدتنا هذه المنصّة على تحويل العملاء المحتملين وزيادة تدفّق الزوار. إضافة إلى ذلك، تتيح HubSpot للمستخدمين إنشاء وأتمتة وقياس وتحسين الحملة التسويقية، وكما ذكرنا فإنّ هذه الأداة تقوم بالقليل من كل شيء، وتساعد في زيادة خبرتك في مجال أتمتة التسويق الأمر الذي سينعكس إيجابًا على فعّالية الشركة. 7. AdRoll يستخدم ما يزيد عن 30,000 معلن حول العالم منصّة AdRoll، وقد ساعدتنا هذه المنصّة في الوصول إلى عملائنا بصورة أسهل. يمكن استخدام هذه المنصّة في إضافة الإعلانات ومراقبة أدائها، وقد ساهمت وبفعّالية في عرض شركتنا على شريحة أوسع من الناس. ونتيجة لذلك أصبح بإمكاننا إجراء التعديلات اللازمة على حملتنا التسويقية لضمان الأداء الأفضل. تمتلك AdRoll واجهة استخدام سهلة وبسيطة، ويمكن ربطها مع تطبيقات التسويق الأخرى، وهذه الميزة توفّر الكثير من الوقت، فضلًا عن أنّك ستحصل في هذه الحالة على أفضل النتائج من كلا التطبيقين. تختلف الأدوات عن بعضها البعض تتيح منصّات أتمتة التسويق إنشاء وتخصيص الحملات التسويقية بهدف الوصول إلى أوسع شريحة من الناس وتحقيق نجاحات أكبر، وتوفّر هذه المنصّات معلومات يمكن استخدامها في تشخيص نقاط الضعف والقوة في هذه الحملات. وبحسب تجربتنا، فإنّ الاعتماد على منصّة واحدة ليس أمرًا عمليًّا، فلكلّ منصّة ما يميّزها عن الأخرى. تستخدم شركتنا مجموعة من الأدوات المختلفة للحصول على أفضل نتيجة ممكنة من كلّ منصّة، وجمع الكثير من الموارد المرتبطة بأتمتة التسويق. ترجمة - وبتصرّف - للمقال 7 Marketing Automation Tools That Will Make Your Social Enterprise More Efficient لصاحبته Lucy Benton. حقوق الصورة البارزة محفوظة لـ Freepik
  9. Lumen هو إطار عمل مصغّر Micro-framework مبني باستخدام إطار العمل Laravel، وهما من صنع Taylor Otwell. صُمّم Lumen لتطوير الخدمات المصغّرة مثل التطبيقات الصغيرة أو خدمات الويب، والهدف من تطويره هو الحصول على أقصى قدر من السرعة، فقد تم استبدال مكوّن التوجيه Symfony في Laravel بـ FastRoute في Lument لتحسين الأداء وزيادة السرعة. في هذا الدرس سننشئ واجهة برمجية بنمط RESTful، وستعمل هذه الواجهة البرمجية على تخزين وعرض المعلومات الخاصّة بالكتب. تثبيت Lumen سنستخدم Composer لتثبيت lumen، لذا سنتحقّق من وجود هذه المكتبة في النظام، وذلك بكتابة الأمر التالي في الطرفية أو في سطر الأوامر: composer إن ظهرت أوامر Composer فهذا يعني أنّه مثبت في الجهاز، أمّا في حالة عدم تثبيت Composer يمكنك الاطلاع على طريقة التثبيت في هذا المقال. بعد تثبيت composer توجّه إلى المجلّد الجذر في الخادوم: cd /var/www/html لمستخدمي نظام ويندوز سنفترض أن المستخدم يمتلك نسخة من خادوم Wamp في الجهاز، لذا يمكن التوجّه إلى المجلّد الجذر في الخادوم بواسطة الأمر التالي: cd wamp\www والآن سنخبر composer بأنّ ينشئ مشروع Lumen باسم “lumen_rest_ce” باستخدام حزمة “laravel/lumen”: composer create-project laravel/lumen lumen_rest_ce سينشئ هذا الأمر مجلّدًا باسم “lumen_rest_ce” ويثبت جميع ملفّات إطار العمل Lumen إضافة إلى جميع الاعتماديات المتعلّقة به. أداة Artisan موجودة في Lumen كما هو الحال في Laravel، ولكنّها تدعم عددًا أقلّ من الأوامر، ويمكنك الاطلاع على قائمة الأوامر بكتابة الأمر التالي في سطر الأوامر: php artisan لاحظ أنّ الأمر serve والمسؤول عن تشغيل التطبيق على الخادوم غير متوفّر في Lumen لذا سنستعين بخادوم التطوير الخاصّ بلغة PHP لتشغيل Lumen وكما يلي: php -S localhost:8000 -t public افتح المتصفّح الآن وتوجّه إلى العنوان localhost:8000. إن ظهر لك رقم الإصدار الخاص بـ Lumen فهذا يعني أنّ عملية التثبيت قد تمّت بنجاح. الإعدادات أنشئ قاعدة بيانات mysql باستخدام phpmyadmin أو أي عميل Mysql آخر، ثمّ عدّل ملف إعدادات Lumen في مجلد المشروع والذي يحمل الاسم “lumen_rest_ce/.env” بالصورة التالية: DB_CONNECTION=mysql DB_HOST=localhost DB_DATABASE=lumen_rest_ce DB_USERNAME=root DB_PASSWORD=your_password افتح الملف lumen_rest_ce/bootstrap/app.php وأزل علامات التعليق من السطرين التاليين: $app->withFacades(); $app->withEloquent(); إزالة التعليق عن هذين السطرين يسمح لنا باستخدام فئة Facade و Eloquent ORM في مشروعنا. التهجير Migration سنكتب الآن مخطّط قاعدة البيانات ونهيّئه لعملية التهجير، حيث سننشئ جدولًا باسم book يتضمّن ستة أعمدة. المعرّف id (قيمته رقمية int وتتزايد تلقائيًا)، العنوان title (من نوع varchar) الكاتب author (من نوع varchar)، الرقم المعياري الدولي للكتاب isbn (من نوع varchar) وحقلي تاريخ الإنشاء وتاريخ التعديل. سنستخدم عملية التهجير والتي هي بمثابة نظام إدارة نسخ خاصّ بقواعد البيانات. اكتب الأمر التالي في سطر الأوامر: php artisan make:migration create_books_table --create=books سينشئ هذا الأمر ملف تهجير في المجلد dbaatase/migration. يتضمّن هذا الملف صنفًا يحمل الاسم CreateBooksTable والذي يضمّ بدوره تابعين الأول هو up حيث سنكتب مخطّط البيانات، أما الآخر فهو down وهو التابع المسؤول عن حذف الجدول. عدّل الملف ليصبح بالصورة التالية: use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateBooksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('books', function(Blueprint $table) { $table->increments('id'); $table->string('title'); $table->string('author'); $table->string('isbn'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('books'); } } لإنشاء الجدول في قاعدة البيانات سنحتاج إلى تهجير أو تنفيذ ملف التهجير الذي أنشأناه قبل قليل وذلك بواسطة الأمر التالي: php artisan migrate النموذج Model أنشئ الآن نموذج Book ضمن الملف app/Book.php وأضف إليه الشيفرة التالية: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Book extends Model { protected $fillable = ['title', 'author', 'isbn']; } ?> أنشئ كذلك ملفّ المتحكّم BookController.php في المجلد app/Http/Controllers وأضف إليه الشيفرة التالية: <?php namespace App\Http\Controllers; use App\Book; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class BookController extends Controller{ ..... ..... } ?> التوجيه Routing افتح الملف web.php في المجلد routes وستجد أنّه يتضمن مسارًا معرّفًا مسبقًا: $app->get('/', function() use ($app) { لغرض كتابة واجهة برمجية بنمط RESTful سنحتاج إلى كتابة المزيد من المسارات وتوابع المتحكّمات المرتبطة بها، وحسب الجدول التالي: التابع عنوان Url Controller@method GET /api/v1/book BookController@index جميع الكتب GET {api/v1/book/{id BookController@getbook إحضار الكتاب حسب المعرّف id POST /api/v1/book BookController@createBook إنشاء سجل جديد في الجدول PUT {api/v1/book/{id BookController@updateBook تحديث الكتاب حسب المعرّف id DELETE {api/v1/book/{id BookController@deleteBook حذف الكتاب حسب المعرّف id لاحظ أنّنا أضفنا v1 إلى جميع المسارات ونقصد به الإصدار الأول، وهذا من الممارسات التي ينصح باتباعها عند إنشاء خدمات الويب. حسب الجدول السابق فإن ملف web.php سيبدو كالتالي: $app->get('/', function() use ($app) { return 'Lumen RESTful API By Hsoub Academy (<a class="vglnk" href="https://academy.hsoub.com" rel="nofollow"><span>https</span><span>://</span><span>academy.hsoub</span><span>.</span><span>com</span></a>)'; }); $app->get('api/v1/book','App\Http\Controllers\BookController@index'); $app->get('api/v1/book/{id}','App\Http\Controllers\BookController@getbook'); $app->post('api/v1/book','App\Http\Controllers\BookController@createBook'); $app->put('api/v1/book/{id}','App\Http\Controllers\BookController@updateBook'); $app->delete('api/v1/book/{id}','App\Http\Controllers\BookController@deleteBook'); يمكننا كذلك تجميع المسارات حسب لاحقة معيّنة أو حسب نطاقات الأسماء، وبهذا لن نكون بحاجة إلى إضافة api/vi ولا إلى كتابة App\Http\Controllers في جميع المسارات. عدّل الشيفرة السابقة لتصبح بالصورة التالية: $app->get('/', function() use ($app) { return 'Lumen RESTful API By Hsoub Academy (<a class="vglnk" href="https://academy.hsoub.com" rel="nofollow"><span>https</span><span>://</span><span>academy.hsoub</span><span>.</span><span>com</span></a>)'; }); $app->group(['prefix' => 'api/v1','namespace' => 'App\Http\Controllers'], function($app) { $app->get('book','BookController@index'); $app->get('book/{id}','BookController@getbook'); $app->post('book','BookController@createBook'); $app->put('book/{id}','BookController@updateBook'); $app->delete('book/{id}','BookController@deleteBook'); }); المتحكّم والآن عدّل الملف BookController.php وأضف إليه التوابع التي عرّفناها في ملف web.php السابق: <?php namespace App\Http\Controllers; use App\Book; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class BookController extends Controller{ public function index(){ $Books = Book::all(); return response()->json($Books); } public function getBook($id){ $Book = Book::find($id); return response()->json($Book); } public function createBook(Request $request){ $Book = Book::create($request->all()); return response()->json($Book); } public function deleteBook($id){ $Book = Book::find($id); $Book->delete(); return response()->json('deleted'); } public function updateBook(Request $request,$id){ $Book = Book::find($id); $Book->title = $request->input('title'); $Book->author = $request->input('author'); $Book->isbn = $request->input('isbn'); $Book->save(); return response()->json($Book); } } اختبار الواجهة البرمجية أصبحت الواجهة البرمجية جاهزة الآن للاختبار، وسنستخدم الأداة CURL لإجراء الاختبار: curl -I <a class="vglnk" href="http://localhost:8000/api/v1/book" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span></a> curl -v -H "Accept:application/json" <a class="vglnk" href="http://localhost:8000/api/v1/book/2" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span><span>/</span><span>2</span></a> curl -i -X POST -H "Content-Type:application/json" <a class="vglnk" href="http://localhost:8000/api/v1/book" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span></a> -d '{"title":"Test Title","author":"test author","isbn":"12345"}' curl -v -H "Content-Type:application/json" -X PUT <a class="vglnk" href="http://localhost:8000/api/v1/book" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span></a> -d '{"title":"Test updated title","author":"test upadted author","isbn":"1234567"}' curl -i -X DELETE <a class="vglnk" href="http://localhost:8000/api/v1/book/2" rel="nofollow"><span>http</span><span>://</span><span>localhost</span><span>:</span><span>8000</span><span>/</span><span>api</span><span>/</span><span>v1</span><span>/</span><span>book</span><span>/</span><span>2</span></a> تتيح الإضافة Postman إجراء الاختبارات على الواجهات البرمجية بنمط RESTful وبسهولة. بعد تثبيت هذه الإضافة توجّه في متصفح Chrome إلى العنوان chrome://apps/ لعرض الإضافات المثبّتة وتشغيل POSTMAN. ختامًا ها قد أصبحت الواجهة البرمجية البسيطة التي أنشأناها جاهزة، ولكن لا زال ينقصها الكثير من الخصائص كالاستثياق والتحقّق من البيانات ومعالجة الأخطاء وغير ذلك الكثير. ترجمة - وبتصرّف - للمقال RESTful API in Lumen, A Laravel Micro Framework لصاحبه Arkaprava Majumder.
  10. قد تحتاج في بعض الأحيان إلى تشغيل شيفرة معيّنة دون انتظار المستخدم للقيام بذلك، يمكنك - والحال هذه - أن تنفّذ الشيفرة في الخلفية وأن تخفيها عن المستخدم، وبهذا تزيد من سرعة وفعّالية موقعك الإلكتروني. تعتمد هذه الطريقة على ما يسمى بشيفرات الصدفة Shell script في نظام Linux، حيث يتم تشغيل العمليات في الخلفية، ويمكنك إضافة مهمّة (كأن يكون أمرًا أو شيفرة) في الخلفية وذلك بإضافة الرمز & إلى نهاية سطر الأوامر، والذي سيؤدي إلى وضع الأمر في الخلفية وتهيئة الطرفية لاستقبال أوامر أخرى. يصطلح على الأمر الذي يتم في الخلفية بالشغل Job. جدير بالذكر أنّه يمكن كتابة أوامر أخرى في الوقت الذي يتم فيه تشغيل الأمر في الخلفية. {command} & // مثال: ls -l & exec php index.php > /dev/null 2>&1 & echo $! يمكن التحقق من العمليات التي يتم إجراءها في الوقت الحاضر في الخلفية على Linux بواسطة الأوامر التالية: ps -l (يسرد هذا الأمر جميع العمليات) ps -ef (يسرد هذا الأمر جميع العمليات مع تفاصيل كاملة) ولتنفيذ الأمر من خلال شيفرة php في الخلفية يمكن استخدام الشيفرة التالية: nohup exec arg1 arg2 > /dev/null & // مثال: nohup exec php process.php hello world > /dev/null & ما هو nohup؟ في معظم الأحيان تقوم بتسجيل الدخول إلى الخادوم البعيد من خلال ssh، ويؤدي الخروج من الخادوم إلى إلغاء جميع شيفرات الصدفة والأوامر التي يتم تنفيذها في تلك اللحظة. ولكن تحتاج بعض الأشغال والأوامر وقتًا طويلًا للتنفيذ لذا يستحسن أن تنفّذ الشغل في الخلفية، ولكن إن سجلت الخروج من النظام، فإن الصدفة ستقوم بإيقاف جميع الأشغال الجارية. هنا يأتي دور nohup. تتيح هذه الأداة تنفيذ الأوامر والعمليات وشيفرات الصدفة وضمان استمرار عملها في الخلفية حتى بعد تسجيل الخروج من الصدفة. nohup command syntax: nohup command-name & ما هو exec؟ يستخدم هذا الأمر لتنفيذ العمليات في Linux، ويمكن من خلاله تنفيذ أمر واحد أو أكثر في نفس الوقت. كيف تستخدم هذه المكتبة في شيفرتك؟ الخطوة الأولى: أنشئ ملفّين الأول باسم index.php والثاني process.php. الخطوة الثانية: استورد الملف PHPBackgroundProcesser.php إلى ملف index.php الخطوة الثالثة: أنشئ نسخة instance من الصنف BackgroundProcess. يمكنك الآن اتباع إحدى الطرق التالية: الطريقة الأولى: $proc=new BackgroundProcess('exec php <BASE_PATH>/process.php hello world'); الطريقة الثانية: $proc=new BackgroundProcess(); $proc->setCmd('exec php <BASE_PATH>/process.php hello world'); $proc->start(); الطريقة الثالثة: $proc=new BackgroundProcess(); $proc->setCmd('exec php <BASE_PATH>/process.php hello world')->start(); يمكنك كذلك تنفيذ عنوان PHP URL في الخلفية دون الحاجة إلى تحديد ملف بصيغة .php. $process=new BackgroundProcess("curl -s -o <Base Path>/log/log_storewav.log <PHP URL to execute> -d param_key=<Param_value>"); يمكن معرفة العمليات التي يتم تنفيذها بواسطة الشيفرة التالية: $proc=new BackgroundProcess(); print_r($proc->showAllPocess()); أما إيقاف العمليات فيكون عن طريق الشيفرة التالية: $proc=new BackgroundProcess(); $proc->setProcessId(101)->stop(); //set the process id. ترجمة - وبتصرّف - للمقال How to run a php script in background لصاحبه Sanjay Panda.
  11. تقدّمت منذ فترة بطلب إلى مطوّري إطار عمل Laravel لإضافة مكتبة JavaScript مشابهة لتلك الموجودة في إطار العمل Ruby on Rails. إذ تقدّم المكتبة المتوفرة في إطار Rails مجموعة من الخصائص المفيدة التي يمكن إضافتها إلى شيفرة HTML للحصول على المزيد من الوظائف التي تسهّل على المطوّر أداء الكثير من المهامّ الشائعة. أجري نقاش حول هذا الموضوع وتمخّض النقاش عن الاقتراح التالي: إما أن يصار إلى إنشاء حزمة Composer من طرف ثالث، أو أن المكتبة التابعة لإطار العمل Rails صالحة للاستخدام في Laravel. وفقًا للمقترح السابق قرّرت استخدام مكتبة UJS التابعة لـ Rails في أحد مشاريعي ورحت أتفحّص الطرق التي يمكن من خلالها استخدام نفس الخصائص في الإصدار الرابع من Laravel. ولسوء الحظ لا يمتلك Laravel نفس التوابع المساعدة الموجودة في Rails والمسؤولة عن أداء وظائف معيّنة، ولكن لا زال بالإمكان تفعيل هذه الوظائف في المكان الذي ترغب فيه باستخدام الخواص الملائمة، ومن المؤكّد أن هذه الوظائف ستعمل حسب المطلوب في أي إطار عمل آخر. البداية بعد أن تربط مكتبتي jQuery و Rails UJS مع ملف HTML ستحتاج إلى إجراء بعض التعديلات السريعة. سنحتاج أوّلًا إلى إعداد مكتبة UJS للعمل مع رمز CSRF على فرض أنّك تستخدم هذه الرموز في تطبيقاتك (أنصحك باستخدامها)، لذا سنضع وسمي <meta> في بداية المستند: <meta name="csrf-param" content="_token"> <meta name="csrf-token" content="{{ csrf_token() }}"> يخبر الوسم الأول مكتبة UJS بالاسم الذي يجب استخدامه لرمز CSRF عند إنشاء الطلب، أما الوسم الثاني فيخبر المكتبة بوسم CSRF الذي يجب استخدامه. يستخدم Laravel افتراضيًا token_ كاسم للمعامل (ألق نظرة على ملف filters.php للمزيد من المعلومات)، أما التابع ()csrf_token فيضيف رمز الحماية إلى الطلب. خاصية data-method هذه الخاصية مفيدة جدًّا عند استخدام للروابط، إذ تخطف مكتبة UJS النقرة على الرابط وتنشئ طلبًا باستخدام فعل Http الذي نقدّمه إلى الخاصية. مثال: <a href="posts/1" data-method="delete" rel="nofollow">Delete this post</a> عند النقر على الرابط، يتم إنشاء طلب من نوع DELETE بدلًا من الطلب الاعتيادي GET والذي ينشأ من مثل هذه الروابط، وبهذا يمكنك إجراء أحداث بنمط RESTful في تطبيقك دون الحاجة إلى الاستمارات. إن كنت ترغب في إنشاء روابط مشابهة لهذا الرابط في Laravel فإليك المثال التالي والذي نستخدم فيه دالة link المساعدة: {{ link_to_route('posts.destroy', 'Delete this post', $post->id, ['data-method' => 'delete', 'rel' => 'nofollow']) }} جدير بالذكر أنّه يجب إضافة الخاصية rel="nofollow" عند استخدام هذه الدالة المساعدة لضمان عدم فهرسة محركات البحث لهذا الرابط. خاصية data-confirm هذه الخاصية مفيدة للتحقّق من الموافقة على إجراء الحدث قبل الاستمرار، وتتم عملية التحقّق هذه بواسطة مربع التنبيه الذي يظهر بواسطة الدالة confirm() في JavaScript، ويمكن استبدال مربّع التنبيه هذا بآخر ذي شكل أجمل حسب الرغبة. تعمل هذه الخاصية بصورة جيّدة مع المثال السابق، فإن كان الرابط أو الزرّ يؤدّي إلى حذف شيء ما فيستحسن حينئذٍ التحقّق من الرغبة في القيام بذلك قبل إجراء عملية الحذف. <a href="posts/1" data-method="delete" data-confirm="Are you sure you want to delete this post?" rel="nofollow">Delete this post</a> إن ألغى المستخدم صندوق التأكيد هذا لن يتم تنفيذ الحدث، والعكس بالعكس. جدير بالذكر أنّك لست ملزمًا باستخدام هذه الطريقة مع خاصية data-method بل يمكن استخدامها مع أي حدث ترغب في التحقق منه قبل إجراءه. خاصية data-disable قد ترغب أحيانًا في تعطيل زرّ معين بعد النقر عليه مباشرة لإتاحة الفرصة لاكتمال الطلب وفي حال فشل الطلب تعيد تفعيل الزرّ مرة أخرى. تتيح لك مكتبة UJS القيام بهذا الأمر بواسطة خاصّية data-disable. <input type="submit" value="Save post" data-disable> هكذا سيتم تعطيل الزر بعد النقر عليه وستمنع المستخدم من النقر المستمر على الزر وإنشاء 10 سجلات جديدة في قاعدة البيانات. بالنسبة لمستخدمي Laravel يمكن الاستفادة من هذه الخاصّية باستخدام منشئ الاستمارات form builder. {{ Form::submit('Save post', ['data-disable']) }} خاصّية data-disable-with يمكن التوسع في المثال السابق وذلك بتقديم بعض المعلومات المفيدة للمستخدم، فعند تعطيل الزرّ يظهر نصّ يخبر المستخدم بأنّ الطلب في طور الإنشاء في الخلفية. <input type="submit" value="Save post" data-disable-with="Saving this post..."> والآن عندما يكون الزرّ معطلًا، يتم استبدال النص بعبارة تدلّ على أن النقر على الزرّ قد أدى إلى حدوث شيء ما في الخلفية. خاصّية data-remote عند إضافة الخاصّية data-remote إلى الاستمارة، تقوم مكتبة UJS بإرسال الاستمارة كطلب Ajax. وستأخذ المكتبة كل شيء بالحسبان (طريقة الإرسال، التحقق من الموافقة على الإجراء… الخ) قبل إرسال الاستمارة. <form action="posts" method="post" data-remote> <!-- Form goes here. --> </form> ويمكن التعامل مع الاستجابة الواردة بعد نجاح الطلب بكل سهولة، فإن استجاب المتصفّح بواسطة JavaScript فستنفّذ الاستجابة فور اكتمال الطلب. على سبيل المثال، قد تختار إعادة توجيه المستخدم بعد تنفيذ طلب للحذف: window.location.href = '{{ route('posts.index') }}'; أو لنقل مثلًا أنّك تستخدم رابطًا لحذف مقالة من صفحة تتضمن قائمة بالمقالات المتوفّرة في المدونة، وترغب في إخفاء المقالة بعد حذفها مباشرة. <a href="{{ route('posts.destroy', $post->id) }}" data-method="destroy" data-confirm="Delete this post?" rel="nofollow" data-remote>Delete this post</a> يمكن استخدام الشيفرة التالية لإخفاء المقالة: $('#post-{{ $post->id }}').fadeOut(); وهكذا، تُحذف المقالة من قاعدة البيانات والعرض في آن معًا. خاصّية data-type: إن استخدمت الخاصّية السابقة data-remote يمكنك كذلك استخدام خاصية data-type لتحديد هيئة البيانات التي يتم إرسالها إلى الخادوم. فعلى سبيل المثال يمكن إرسال الاستمارة على هيئة Json: <form data-type="json"> الأحداث البعيدة عند استخدام خاصّية data-remote يمكن الوصول إلى الأحداث المختلفة في طلب Ajax لتأدية بعض المهامّ الإضافية. إذ تطلق مكتبة UJS عددًا من الأحداث المساعدة خلال دورة حياة الطلب والتي من شأنها أن تساعد في بناء تطبيقات أكثر تعقيدًا. ajax:before ينطلق هذا الحدث قبل حدوث أي شيء، وإيقاف هذا الحدث يؤدي إلى إلغاء الطلب. ajax:beforeSend: ينطلق هذا الحدث قبل إرسال طلب Ajax مباشرة، وإيقاف الحدث يؤدي إلى إلغاء الطلب. ajax:send: ينطلق عند إرسال طلب Ajax. ajax:success: ينطلق بعد اكتمال الطلب بنجاح. ajax:error: ينطلق بعد فشل إرسال الطلب. ajax:aborted:required: ينطلق في حال وجود حقول إلزامية فارغة في الاستمارة، وفي حال إيقاف الحدث يتم إرسال الاستمارة. ajax:aborted:file: ينطلق في حال وجود حقول ملفات غير فارغة في الاستمارة، ويتم تجاهل الطلب في حال توقّف الحدث. آمل أن يكون هذا الموضوع مفيدًا لكل من يرغب في استخدام مكتبة UJS التابعة لإطار العمل Ruby on Rails مع إطارات العمل الأخرى مثل Laravel، إذ أرى أن هذه المكتبة مفيدة ولا يجوز أن تكون حكرًا على مستخدمي إطار Rails. ترجمة - وبتصرّف - للمقال Using Rails UJS in Laravel 4 (or any other framework) لصاحبه Dwight Conrad Watson.
  12. سواء أكنت في طور بناء موقع إلكتروني لأحد العملاء وترغب في إطلاق حملة تسويقية، أو كنت ترغب فقط في زيادة نسب المشاهدة والوصول إلى موقعك الإلكتروني، فإنّ التهيئة لمحركات البحث هي من الأمور المهمّة لتحقيق ذلك، وربّما تكون العامل الأساسي في نجاح أو فشل المدوّنات أو المشاريع التجارية على شبكة الإنترنت. وعلى الرغم من أنّ محركات البحث الحديثة قد وصلت إلى مستويات كبيرة من التطوّر، وعلى الرغم من أنّ خوارزميات البحث تتطوّر بصورة يومية، إلّا أنّ محرّكات البحث هذه غير قادرة على استيعاب وفهم صفحات الويب بنفس الأسلوب الذي يتّبعه الإنسان. سنتعرّف في هذا المقال على كيفية تهيئة محرّكات البحث في تحديد الهدف من كل صفحة من صفحات الموقع باتباع بعض الخطوات البسيطة، وسنتعرّف كذلك على فائدة عملية التحسين هذه بالنسبة للمستخدمين. لو أخذنا بنظر الاعتبار أن 89% من العملاء يقدمون على شراء المنتجات بعد أن يبحثوا عنها بواسطة محرّكات البحث، فستتجلّى لنا الأسباب التي تجعل من قابلية رؤية محركات البحث للموقع الإلكتروني أمرًا مهمًّا للغاية. ترفع التهيئة لمحركات البحث من قابلية رؤية المشروع التجاري على الإنترنت وتزيد تدفق الزوّار على الموقع الإلكتروني 91.5% من تدفّق الزوّار القادم من محرّك البحث Google يأتي من صفحة النتائج الأولى فقط، في حين أن أقل من 9% من الزوّار فقط ينتقلون إلى الصفحة الثانية في النتائج. 61.5% من تدفّق الزوار يأتي من النتائج الثلاثة الأولى فقط. (دراسة أجرتها مؤسسة Chitika Insights) يمكننا أن نلاحظ وبوضوح مدى أهمّية الترتيب الذي يأخذه الموقع الإلكتروني في نتائج البحث على Google وتأثيرها المباشر على قابلية رؤية الموقع الإلكتروني وعدد الزوّار. وينتج عن الوصول إلى مواقع متقدّمة في نتائج البحث الحصول على الغالبية العظمى من النقرات؛ لذا فإن الوصول إلى المراتب المتقدّمة في نتائج البحث سيؤدي إلى زيادة كبيرة في عدد زوّار موقعك الإلكتروني. تركّز عملية تهيئة محرّكات البحث على إنشاء عناوين وأوسمة وأوصاف meta ذات علاقة بكلمة مفتاحية تظهر في صفحة النتائج، وتساعد الأوسمة والأوصاف المهيّئة بصورة جيّدة إلى زيادة عدد النقرات وهذا سيؤدي إلى زيادة اهتمام عملائك بما تقدّمه إليهم في موقعك الإلكتروني. إليك وجهة نظري تجاه هذا الموضوع ملخّصة في جملة واحدة: التهيئة لمحركات البحث فعّالة من حيث التكلفة تعدّ التهيئة لمحركات البحث إحدى أكثر استراتيجيات التسويق كفاءة وفعّالية من حيث التكلفة، لأنّها تستهدف المستخدمين الذي يبحثون عن منتجاتك وخدماتك في الإنترنت، وفي الوقت نفسه تصبح عملية الحصول على مجموعة زوّار طبيعية Orgainc Listing مجّانية تقريبًا. فعندما يحتلّ موقعك مراتب متقدّمة في نتائج البحث لن تكون حينها بحاجة إلى تخصيص ميزانية للإعلان والترويج لموقعك الإلكتروني، وهذه هي إحدى الميّزات الرئيسية للتهيئة لمحركات البحث، إذ يكفي أن تهيّئ موقعك الإلكتروني لمحرّكات البحث بصورة جيّدة ولن تحتاج بعدها إلى تحمّل أي تكاليف إضافية لجذب المزيد من العملاء المهتمّين. تمنح التهيئة لمحركات البحث المصداقية لمشروعك التجاري صاحب تزايد استخدام الحواسيب والهواتف المحمولة اعتماد الناس بصورة أكبر على محركات البحث. ويثق الناس بأنّ النتائج الأولى في Google تابعة لشركات ذات سمعة جيدة، وبهذا يمكن لعلامتك التجارية أن تحصل على المزيد من الثقة وذلك باستخدام التهيئة لمحركات البحث. تزيد التهيئة لمحركات البحث من سهولة تصفّح الموقع إن تسهيل عملية تصفح موقعك الإلكتروني بالنسبة لمحركات البحث يؤدي بصورة تلقائية إلى إنشاء موقع إلكتروني سهل التصفح بالنسبة للمستخدمين. فإعادة ترتيب هيكلية الموقع وإنشاء خرائط موقع Sitemaps منظّمة، واستخدام عناوين URL صديقة لمحركات البحث، تسهل من قابلية وصول المستخدمين إلى المعلومات التي يوفّرها الموقع الإلكتروني. ما هي الخطوات التي يمكنك اتباعها لتحسين التهيئة لمحركات البحث لديك هناك الكثير من المقالات المتوفّرة على شبكة الإنترنت والتي تغطّي وبالتفصيل كلّ ما تحتاج إلى معرفته حول موضوع تحسين محرّكات البحث، ويمكن الرجوع إلى سلسلة أساسيات SEO للمدوّنين للاطلاع. ولكن من الضروري التركيز على أمور ثلاثة: إجراء التحسينات على صفحات الموقع On-page optimization سواء أكنت ترغب في توظيف محترف في هذا المجال، أو استخدام إضافات مثل Yoast أو All-in-One SEO Pack أو Ultimate SEO) أو الاعتماد على خبرتك في التهيئة لمحركات البحث، فيجب عليك إجراء التحسينات على صفحات الموقع. وهذا يعني أنّ عليك التركيز على تطوير جميع النواحي التقنية (عناوين URL، وسوم العنوان وبيانات meta، كثافة الكلمة المفتاحية، بنية الموقع، الروابط الداخلية، سرعة الموقع، تحسين المحتوى، المقروئية في الأجهزة المحمولة…) على صفحات الموقع الإلكتروني مباشرة. جودة المحتوى من الواضح أنّ Google ومحرّكات البحث الأخرى قد بدأت تركّز تدريجيًّا على جودة وموثوقية المحتوى بدلًا من التحسين على صفحات الموقع. صحيح أنّ تحسين وسوم meta وبنية الموقع لا زال أمرًا ضروريًا، ولكن لم يعد بمقدور أحد أن ينكر أنّ للمحتوى الجيد ولتجربة الاستخدام التي تركّز على المستخدم قصب السبق في مضمار الحصول على نتائج بحث طبيعية organic، وكما يقول Bill Gates: “المحتوى هو الملك”، ويبدو أن محرّكات البحث قد أدركت صحّة هذه المقولة أخيرًا. تتطوّر خوارزميات البحث كلّ يوم، وقد بدأت Google بالاقتراب من الهدف الذي تسعى لتحقيقه وهو: “تنظيم معلومات العالم وجعلها مفيدة وفي متناول الجميع”، وذلك من خلال تحديد الهدف الذي تتوخّاه كلّ صفحة من صفحات الموقع الإلكتروني ومعرفة مقدار الفائدة الذي تقدّمه للمستخدمين. إنشاء روابط موثوقة يمكنك أن تضمن حصول موقعك الإلكتروني على ترتيب متقدّم في محرّكات البحث وذلك بالتخلّص من عادات SEO القديمة مثل تبادل الروابط، والتركيز على الروابط الخلفية الموثوقة backlinks والقادمة من مواقع إلكترونية معروفة وموثّقة. والمقصود بالروابط الموثوقة هي تلك الروابط التي تأتي من: موقع إلكتروني يمتلك تأثيرًا فعليًّا وتدفّقًا جيّدًا للزوّار. صفحة ذات علاقة بموقعك الإلكتروني أو المحتوى الذي تقدّمه. رابط (نصّي) غير خبيث، في موقع بارز من الصفحة، ونصّ الرابط ذو علاقة بالمحتوى. كيف أعرف أنّي أحقّق نتائج جيدة ما الذي يدفعنا إلى الاهتمام بهذا الأمر، وما الذي يدفعك إلى الاهتمام بتدفّق الزوّار إلى موقعك الإلكتروني؟ إن الهدف الرئيسي من موقعك الإلكتروني هو جلب العملاء سواء القدماء منهم أم المحتملين، ويمكنك التعرّف على كفاءة موقعك الإلكتروني في أداء وظيفته من خلال مراقبة وتحليل البيانات القادمة من زوّار الموقع. إذ يمكن من خلال مراقبة النتائج معرفة ما إذا كانت الجهود المبذولة مجدية أم لا، وتحديد المشاكل التي قد تتطلّب إجراء بعض التعديلات. راقب الترتيب على محرّكات البحاث يعد الترتيب حسب التهيئة لمحركات البحث مصدر الدخل الرئيسي لعدد كبير من المشاريع التجارية، ولكن البقاء في القمة يتطلبّ متابعة مستمرة لترتيب كلمتك المفتاحية ومدى مجاراتك لمنافسيك في هذا المجال. ويمكنك الاستعانة بالإضافة ManageWP للحصول على الكلمات المفتاحية الاحترافية ومعلومات عن المنافسين في مجال عملك. وفي الوقت نفسه ستتوفّر لدينا معلومات جيّدة يمكن الاستفادة منها في إجراء تحسينات إضافية على الموقع الإلكتروني وتقديم حزم صيانة موسّعة expanded maintenance packages لعملائنا. حلّل أعداد الزوّار في موقعك الإلكتروني يمكنك التعرف على مدى فاعلية التهيئة لمحركات البحث والجهود التي تبذلها في التسويق لموقعك الإلكتروني وذلك من خلال متابعة عدد الزوّار الذين يرتادون موقعك الإلكتروني شهريًّا، فإن كانت تحافظ على مستوى ثابت في تدفّق الزوّار فهذا يعني أنّ جهودك التسويقية غير فعّالة ولا تأتي بأي نتيجة تذكر. يمكنك الاستفادة من أدوات التحليل مثل Google Analytics لمشاهدة مصادر تدفق الزوّار في موقعك الإلكتروني، وهكذا يصبح لديك تصوّر كافٍ حول هذا الموضوع وستشخّص استراتيجية/قناة التسويق الأكثر فعّالية. وأبسط طريقة للقيام بذلك هي ربط حسابك في Google Analytics مع لوحة التحكم الخاصّة بموقعك الإلكتروني ومراقبة الزيارات من خلال Google Analytics على ManageWP. ويستحسن كذلك أن تجمع حسابات Google Analytics المختلفة في لوحة تحكّم واحدة، الأمر الذي سيسهّل عليك مراجعة الإحصاءات الخاصّة بكل موقع. الخلاصة تهيئة محركات البحث أمر ضروري بالنسبة لمشروعك التجاري لأن الناس يستخدمون محركات البحث للتعرّف على المنتجات وشرائها عبر الإنترنت. وبما أنّ المجتمع الإلكتروني يكبر يومًا بعد يوم، فلا يجدر بك تجاهل أهمية التهيئة لمحركات البحث في زيادة قاعدة عملائك أو زوّارك. وأنهي المقال بفكرة أخيرة: أصبحت التهيئة لمحركات البحث اليوم مرادفة لقابلية الرؤية، فمن دون إجراء التحسينات ودون وجود محتوى ذي جودة عالية فإن مشروعك التجاري سيكون غير مرئي في السوق الرقمي المعاصر. ترجمة - وبتصرّف - للمقال Why is SEO essential for your business? لصاحبه Marko Tanaskovic. حقوق الصورة البارزة محفوظة لـ Freepik
  13. أعترف بأنّي لا أمتلك خبرة كبيرة في مكتبة Webpacker الجديدة في إطار العمل Ruby on Rails، ولكنّي قرّرت الاعتماد على هذه المكتبة تمامًا والاستغناء كلّيًا عن مكتبة Sprockets للتعامل مع الأصول assets. وباعتباري أحد متّبعي مبدأ Convention Over Configuration فقد حاولت جاهدًا إيجاد الطريقة التي يمكن الاصطلاح عليها في تشييد تطبيق Webpacker. هذه المكتبة في أيامها الأولى لذا أظنّ أنّ فريق مطوري Rails لم يقوموا بهذا الأمر أيضًا، وأعتقد بأنّ مجتمع المطوّرين سيجد حلًّا لهذه المسألة قريبًا. على أي حال، إليك الطريقة التي اتبعتها في استبدال asset pipeline بـ Webpacker. إن كنت ترغب في العمل على مشروع جديد، فاستخدم الأمر: rails new blank --skip-sprockets --webpack ليتم إنشاء تطبيق Rails جديد مع الاستغناء عن مكتبة Sprockets وإضافة المكتبة Webpacker. أما لو كنت ترغب في إضافة Webpacker إلى مشروع قائم فعليك بمراجعة التوثيقات. بعد ذلك احذف بعض الجواهر gems والتي لم نعد بحاجة إليها من ملف Gemfile، وهي sass-rails، uglifier و coffee-rails. كذلك يمكنك التخلص من المجلد app/assets لأنّنا لم نعد بحاجة إليه بعد الآن. لنلق نظرة في البداية على محتويات ملف application.js الذي يتم إنشاؤه افتراضيًّا بواسطة Webpacker. /* eslint no-console:0 */ // This file is automatically compiled by Webpack, along with any other files // present in this directory. You're encouraged to place your actual application logic in // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled. // // To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate // layout file, like app/views/layouts/application.html.erb console.log('Hello World from Webpacker') تشير التعليقات الواردة في هذا الملف إلى أن المجلد app/javascript/packs هو نقطة الولوج entry point إلى الحزم المستخدمة في التطبيق، وأنّ عليك وضع التطبيق الحقيقي في المجلد app/javascript. ترتيب الملفّات والمجلّدات لقد نظّمت تطبيق Webpacker الخاصّ بي كما هو موضح أدناه، والتطبيق يحمل اسم blog. سترى أنّي قد أدرجت تطبيق JavaScript الحقيقي في المجلد app/javascript/blog بدلًا من app/javascript ولم أقم بذلك اعتباطًا. أولًا: يعني هذا أن بمقدوري إضافة العديد من التطبيقات إلى المشروع الواحد وحسب الحاجة، بدلًا من تكديس جميع الشيفرات جنبًا إلى جنب. ثانيًا: ستتيح لي هذه الطريقة امتلاك نقطة ولوج حقيقية للحزم وهذا ما سأوضّحه الآن. blog +-- app | +-- javascript | | +-- blog | | | +-- fonts | | | +-- images | | | +-- styles | | | +-- index.js | | +-- packs | | | +-- application.js لنلق نظرة الآن إلى ملف app/javascript/packs/application.js وهو نقطة الولوج إلى حزمتي، وهو ملفّ بسيط للغاية: import 'blog'; سيتم استيراد التطبيق وتشغيل الملف app/javascript/blog/index.js والذي سيصبح نقطة الولوج إلى تطبيق JavaScript الخاصّ بي. بهذه الطريقة أحافظ على نقطة الولوج بسيطة قدر الإمكان أما ما تبقى من الشيفرة فيكون ضمن التطبيق. جدير بالذكر كذلك أنّك لست ملزمًا بتسمية المجلد - والملفّ - باسم blog، بل يمكنك استخدام أي اسم تشاء، ولكنّني توخيت تبسيط الأمور بجعل اسم المجلد مطابقًا لاسم تطبيق Rails. والآن سنستخدم javascript_pack_tag للإشارة إلى تطبيقنا. javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' مرحلة التطوير عند العمل في بيئة التطوير Development استخدم الأمر bin/webpack-dev-server وستتمّ مراقبة التطبيق وإعادة بنائه عند الحاجة، وإرسال التعديلات إلى المتصفّح. وبعد أن يصبح التطبيق جاهزًا للتجميع Compile يمكن استدعاء الأمر bin/webpack أو rails assets:precompile، ولكن سيتولى الخادوم هذه المهمّة على الأرجح. مكتبتا Turbolinks وRails UJS إن كنت ستستخدم Turbolinks و Rails UJS في تطبيقك فعليك إعداد هاتين المكتبتين وتشغيلهما. من السهل استدعاء المكتبتين بواسطة الأمر //= require في حال كنت تستخدم asset pipline ولكن عند استخدام هاتين المكتبتين كوحدات فالأمر مختلف قليلًا. في البداية علينا تثبيت المكتبتين: yarn add rails-ujs turbolinks بعد ذلك علينا استيراد المكتبتين وتشغيلهما في ملف app/javascript/blog/index.js: import Rails from 'rails-ujs'; import Turbolinks from 'turbolinks'; Rails.start(); Turbolinks.start(); كما تلاحظ فقد اتبعنا نفس الأسلوب في استدعاء كلتا المكتبتين وتشغيلهما. متغيرات البيئة Environment Variables يمكن الوصول إلى متغيرات البيئة عبر الشيفرات الخاصة بنا بعد تجميعها. عادة ما أضيف اللاحقة .erb إلى اسم الملف ثم أنفّذ شيئًا مماثلًا لهذا: <%= ENV['X_ENV_VAR'] %> ولكن هناك طريقة أفضل، إذ يمكن تهجير المتغيرات إلى process.env وكما يلي: export const STRIPE_API_KEY = process.env.STRIPE_API_KEY; أوراق الأنماط Stylesheets يمكن وبكل بساطة استيراد ملفات CSS أو Sass التي ترغب باستخدامها في التطبيق. لقد حدّدت الملف app/javascript/blog/styles/app.scss كنقطة ولوج Sass وبهذا أبقي جميع الملفات في مجلد styles، وتصبح عملية استيرادها إلى التطبيق أمرًا سهلًا للغاية: import './styles/app.scss'; يمكن استخدام المحرّف ~ مع import وستبدأ عملية البحث عن الملف من المجلد node_modules، فلو أردت مثلًا استيراد مكتبة Bootstrap إلى التطبيق يمكنك استخدام الشيفرة التالية: @import '~bootstrap/scss/bootstrap'; الصور لا تختلف الصور عن أوراق الأنماط في شيء، إذ يجب استيرادها في البداية لتتمكن من استخدامها في التطبيق. عادة ما أضع الصور في مجلد app/javascript/blog/images ثم أنشئ ملفًّا باسم index.js في نفس المجلد وظيفته استيراد جميع الصور في المجلد. فعلى سبيل المثال: import './logo.svg'; import './menu-open.svg'; import './menu-close.svg'; عليك الانتباه إلى أنّ هذه الطريقة لن تُضمّن الصور في أوراق الأنماط، وإنما تدفعها إلى Webpacker لتكون متاحة للاستخدام في التطبيق. ويمكنك حينئذٍ استخدام الدالة المساعدة asset_pack_path في العرض للإشارة إلى هذه الملفات. فلو أردت مثلًا استخدام إحدى هذه الصور: = image_tag asset_pack_path('logo.svg') إضافة إلى ذلك يمكنك الإشارة إلى الصور في CSS أو Sass وسيتلقّفها Webpacker بصورة تلقائية. وبصورة عامة يكون مسار الجذر نقطة الولوج الخاصّة بأوراق الأنماط لذا لن تكون بحاجة إلى استخدام المسارات المطلقة. ختامًا كما شاهدت فإن الأمر يتطلب الكثير من العمل، وهذا هو الأسلوب الذي أتبعه في استخدام Webpacker الآن. حاولت البحث عن مقالات تعنى بتفصيل طريقة استخدام Webpacker ولكنّي لم أجد شيئًا يذكر في الوقت الحاضر. أنا متحمّس جدًّا لمعرفة طريقة الاستخدام القياسية لهذه المكتبة هذا في حال تمّ تحديدها في المستقبل. ترجمة - وبتصرّف - للمقال Replacing Rails Asset Pipeline with Webpacker لصاحبه Dwight Conrad Watson.
  14. Composer هو أداة لإدارة الاعتماديات في لغة PHP، تخيل أنّك تعمل على مشروع يتضمن العديد من الاعتماديات التابعة لمشاريع أو مكتبات أخرى. سيدير Composer بالطرق التالية: تحميل مكتبة الاعتمادية من مستودعاتها إلى مشروعك بصورة تلقائية. يمكنك وبكلّ سهولة تحديث مكتبتك عند ظهور إصدار جديد منها. عند تحميل مكتبة الاعتمادية يتحقّق composer من المتطلبات الدنيا للخادوم. سينشئ Composer ملف autoloader.php لجميع المكتبات المحمّلة وسيحمّل الاعتمادية كاملةً في المشروع الذي تعمل عليه. ماذا سيحصل إن لم تستخدم Composer؟ ستضطرّ إلى تحميل مكتبة الاعتمادية يدويًّا. يجب عليك التحقّق من الإصدارات الجديدة للمكتبات دوريًّا، وتحميل الملفات إلى المشروع يدويًّا. يجب عليك تحميل جميع المكتبات إلى مشروعك باستخدام دالتي require أو include. إليك المثال التالي لتوضيح ما سبق: لديك مشروع تعمل عليه باستخدام إطار عمل Cakephp أو Laravel، وترغب في إضافة خاصية إرسال الرسائل إلكترونية إلى المشروع وتحتاج إلى اتصال من نوع SMTP. ستقوم حينها بتحميل إحدى المكتبات المتخصّصة في هذا المجال مثل Phpmailer أو Swiftmailer. إن استخدمت composer للحصول على هذا المكتبات، فسيكون بميسورك تحميل المكتبة المطلوبة مباشرة إلى مجلد vendor ضمن المشروع. وإن حصلت هذه المكتبة على تحديث جديد، يكفي أن تنفّذ أمرًا واحدًا في سطر الأوامر، ولن تكون بحاجة إلى التحقّق ممّا إذا كان التحديث متوافقًا مع الإصدار 5.4 أو 5.3 من php. سيتّضح الأمر أكثر فأكثر من خلال الأمثلة التالية. كيف يتم تثبيت Composer في النظام قبل تثبيت composer يجب التحقّق من أنّك تعمل على الإصدار 5.4 وما بعده من لغة PHP. إن كنت من مستخدمي نظام ويندوز فيمكنك تحميل الملف التنفيذي الخاص بتثبيت Composer وذلك من الرابط: https://getcomposer.org/، وتنصيب Composer في نفس المجلد الذي قمت بتثبيت php.exe فيه. (C:\wamp\bin\php\php5.5.12 مثلاً). أما مستخدمو نظامي Linux و Mac فيمكنهم فتح الطرفية وكتابة الأمر التالي فيها: curl -sS https://getcomposer.org/installer | php سيقوم هذا الأمر بتحميل ملف composer.phar (phar تعني php archive) بواسطة الأداة curl، وللوصول إلى composer من أي مكان في حاسوبك يجب عليك نقل هذا الملف إلى المجلد /usr/bin/composer، وذلك بتنفيذ الأمر التالي في الطرفية: sudo mv composer.phar /usr/bin/composer للتحقق من وجود Composer يكفي الدخول إلى سطر الأوامر في ويندوز أو الطرفية في Linux و Mac وكتابة كلمة composer والضغط على زر الإدخال Enter. إن كان Composer مثبّتًا في جهازك ستظهر شاشة الترحيب التالية إضافة إلى جميع ا لأوامر المستخدمة في composer. تطبيق عملي لاستخدام مكتبة Composer سيبحث Composer عن الملف composer.json حيث سندرج جميع الاعتماديات التي نحتاج إليها في المشروع. لننشئ مجلّدًا جديدًا بواسطة الأمر التالي: mkdir composer_example ادخل إلى المجلد: cd composer_example أنشئ ملف composer.json هنا، وأضف إليه ما يلي: { "require": { "jdorn/sql-formatter": "1.3.*@dev" } } هنا jdorn هو اسم صاحب الحزمة sql-formatter التي نرغب في تثبيتها ضمن المشروع. ولكن قد تتسائل من أين سيأتي Composer بهذه الحزمة. في الواقع هناك موقع إلكتروني آخر هو Packagist يتضمّن جميع المكتبات الشائعة ويمكن تصفّحها من خلال الموقع. مكتبة sql-formatter عبارة عن صنف php صغير الحجم يعمل على تنسيق عبارات SQL حيث يضبط الإزاحات في بداية العبارة تلقائيًا كما يدعم تلوين الكلمات المفتاحية. بعد أن أعددنا ملف composer.json يمكننا تحميل وتنصيب الملفات المطلوبة في مجلد المشروع بواسطة الأمر: composer install سيتم تحميل جميع الملفات المطلوبة ومن ضمنها ملفات autoload إلى المجلد composer_example/vendor. والآن أنشئ ملفًّا باسم index.php في المجلد composer_example واجلب فيه الملف autoload.php باستخدام الدالة require وبذلك سيتمّ تحميل جميع الاعتماديات في هذا الملف. إليك المثال التالي: <?php require "vendor/autoload.php"; $query = "SELECT count(*),`Column1`,`Testing`, `Testing Three` FROM `Table1` WHERE Column1 = 'testing' AND ( (`Column2` = `Column3` OR Column4 >= NOW()) ) GROUP BY Column1 ORDER BY Column3 DESC LIMIT 5,10"; echo SqlFormatter::format($query); ?> لاحظ مدى سهولة وسرعة التعامل مع الاعتماديات بواسطة Composer. لننشئ مشروعًا آخر لنفترض أننا نرغب في إضافة إطار عمل Codeigniter بواسطة Composer. لن نستخدم هذه المرّة الأمر composer install بل سنستخدم الأمر composer create-project لإنشاء مشروع جديد. توجّه إلى موقع Packagist وابحث عن مكتبة Codeigniter، ثم حمّل نسخة من إطار العمل إلى مجلد المشروع الذي تعمل عليه: composer create-project codeigniter/framework مجلد المشروع بعد اكتمال العملية ستجد ملف composer.json في مجلد المشروع، ويمكن إضافة المزيد من الاعتماديات إلى مشروعك بواسطة هذا الملف. لنفترض أنّك ترغب في استخدام حزمة sql-formatter في مشروعك هذا. توجّه إلى ملف composer.json وعدّله ليصبح بالصورة التالية: { "description" : "A way to install CodeIgniter via composer", "name" : "rogeriopradoj/codeigniter", "license": "OSL-3.0", "require": { "php": ">=5.2.4", "jdorn/sql-formatter": "1.3.*@dev" } } ثمّ حدّث الاعتماديات بواسطة الأمر: composer update والآن إن كنت ترغب في رفع هذا المشروع إلى Github أو مشاركته مع أحد الأصدقاء، لن تكون بحاجة إلى إرسال مجلد vendor، بل يكفي أن ترسل الملف composer.json وسيكون بميسور صديقك تحميل جميع الاعتماديات المطلوبة والمستخدمة في المشروع. عليك بتجربة composer، إذ تستخدمه معظم أطر عمل php المعروفة مثل Laravel، Symfony 2 و Yii إضافة إلى بعض حزم php الرائعة التابعة لـ Phpleague. فماذا تنتظر إذًا؟ ترجمة - وبتصرّف - للمقال Composer easy tutorial – php dependency management tool لصاحبه Arkaprava Majumder.
  15. تقدّم المواصفات الجديدة في CSS3 محدّدين Selector مفيدين للغاية هما :valid و :invalid وهي أصناف زائفة pseudo-class يمكن استخدامها مع عناصر الإدخال الخاصة بالاستمارات. لنفترض أن لديك عنصر إدخال تتحقّق من خلاله فيما إذا كان ما أدخله المستخدم صحيحًا أم خاطئًا. لإجراء عملية التحقق ستحتاج إلى إضافة خاصية HTML5 required إلى الوسم الخاص بعنصر الإدخال، وبهذا يمكن الاستفادة من المحدّدين :valid/:invalid لتغيير لون حقل الإدخال ليعرف المستخدم من خلال ذلك أنّ ما أدخله صحيح أو خاطئ. فعلى سبيل المثال يتحول مربع الإدخال إلى اللون الأخضر عندما تكون العبارة صحيحة، وكما يلي: input:required { background: #AAA; } input:valid { background: #0A0; } input:invalid { background: #A00; } سننشئ في هذا الدرس استمارة بنمط Material وسننبّه المستخدم على صحة البيانات المدخلة في الاستمارة من خلال الصنفين الزائفين :valid و :invalid. تتألف الاستمارة من مربع نصّي وحيد وقد أحطنا عنصري input[type="text"] وlabel بعنصر div يحمل المحدّد .form-control من إطار عمل Bootstrap. لدينا أيضًا شريط سيتغير لونه بين الأخضر والأحمر للدلالة على صحة المعلومات المدخلة من عدمها. <div class="form-control"> <input type="text" required /> <span class="bar"></span> <label for="First Name">First Name</label> </div> في البداية سنزيل جميع الحدود المحيطة بمربّع النص باستثناء الحدّ السفلي وسنلوّنه باللون الأزرق ليكون متناسقًا مع نمط التصميم Material. .form-control { position:relative; margin-top:40px; width:400px; } input { border:none; border-bottom:3px solid #34495e; padding:10px 0; width:400px; display:block; font-size:16px; } سيؤدي العنصر label دور ماسك مكان placeholder، لذا سنجعل موقعه مطلقًا مع تعيين المسافة اليسرى والعلوية المناسبة، ليبدو العنصر بهيئة ماسك مكان اعتيادي. label { position:absolute; top:8px; left:5px; font-size:16px; color:#333; transistion: 0.3s ease all; -webkit-transition:0.3s ease all; } والآن عندما يضغط المستخدم أو يجعل التركيز على مربّع النص سنقوم بإلغاء الحدّ السفلي، وسنغير موقع ماسك المكان ليصبح فوق مربع النص ليبدو كـ label. input:focus{ border:none; outline:none; } سيبقى الـ label فوق مربع النص إلى أن يجعل المستخدم التركيز على مربّع النص ويضيف إليه أي معلومات صحيحة. input:focus ~ label, .form-control input:valid ~ label { top:-10px; font-size:12px; left:2px; color:#111; } لن يظهر المحدّد .bar بصورة تلقائية، بمعنى أن عرضه سيكون صفرًا، وإن قمنا بالتركيز على مربع النص فإن عرض المحدّد .bar سيزداد. كما ستلاحظ فقد حدّدنا العرض ضمن الصنفين الكاذبين (:after و :before) حيث سيزداد العرض 50% لكل عنصر زائف، بمعنى أن الزيادة الكلية ستكون 100%، وهكذا سنحصل على تأثير توسّع جميل. .bar:before, .bar:after { content:''; height:3px; width:0; bottom:1px; position:absolute; transition:0.2s ease all; -moz-transition:0.2s ease all; -webkit-transition:0.2s ease all; } .bar:before { left:50%; } .bar:after { right:50%; } input:focus ~ .bar:before, input:focus ~ .bar:after { width:50%; } سنغيّر الآن لون خلفية الشريط حسب صحة أو عدم صحة البيانات المدخلة، وذلك باستخدام الصنفين الزائفين :valid و :invalid. input:valid ~ .bar:before, input:valid ~ .bar:after{ background:#2ecc71; } input:invalid ~ .bar:before, input:invalid ~ .bar:after{ background:#e74c3c; } تعمل هذه الطريقة على متصفحات (+Chrome(10 و (+Firefox(4 و (+Safari(5 و (+Opera(10 و (+IE(10، ولكن لا تعمل على الإصدار التاسع وما دونه من متصفح IE. وجدير بالذكر أنّه لن يتم التحقّق من صحة البيانات بأي شكل من الأشكال، ويمكن استخدام هذه الطريقة في مجال تجربة المستخدم فقط. ترجمة - وبتصرّف - للمقال Form validation in pure css لصاحبه Arkaprava Majumder.
  16. ما هو شعورك عندما تقضي أسابيع أو شهور أو ربّما سنوات في بناء وتطوير منتجك الرائع ثم لا يشتري أحد منك هذا المنتج؟ غالبًا ما يعود سبب إخفاق المنتج اﻷول إلى خطأ واحد وبسيط. عنوان المقال يبدو كعنوان مضلّل يهدف إلى جذب القراء لا أكثر، ولكنّ مضمونه صحيح أيضًا، وبما أنّك قد شعرت برغبة ملحّة في النقر على العنوان، فيمكنني التخمين بأنّك تتحلّى بهاتين الصفتين: أنت شخص مبتكر تحبّ صناعة اﻷشياء. تحب صنع اﻷشياء وبيعها كذلك. ويمكنني أن أضيف إلى الصفة اﻷولى أنّك تمتلك الكثير من الأفكار التي يمكنك من خلالها إنجاز اﻷمور على أتمّ وجه، وأنّك من النوع الذي يمتلك همّة عالية ويشمّر عن ساعديه ويبدأ بكتابة الشيفرات والتصميم والكتابة والتسجيل وغير ذلك من اﻷعمال. تؤدي هذه الرغبة الكبيرة في إنجاز الأعمال - والمعروفة بالانحياز للعمل Action bias - دورًا عظيمًا في حياتك اليومية والمهنية كمستقلّ أو مستشار، فالعالم بحاجة إلى اﻷشخاص الذين يقدمون على إنجاز الأعمال بلا كلل أو ملل. ولكن متى تبدأ بإنشاء مشروعك التجاري؟ انحيازك للعمل سيؤدّي بك إلى الفشل سيدفعك انحيازك للعمل إلى إنشاء منتج رائع، ولكن سرعان ما تجد نفسك عاجزًا عن الإتيان بأي شيء عندما ترغب في دفع الناس إلى استخدام المنتج ونشره وتجربته وشرائه. ستعاني من عدم اهتمام العملاء بمنتجك، وهو بمثابة جدار كبير عليك تجاوزه؛ لذا ستحاول أن تعيد تمحور عملك وستحاول جاهدًا البحث عن سوق ملائم لمنتجك. ستبدأ بإجراء الاتصالات الباردة، وستجرّب أساليب مختلفة لعباراتك التسويقية بحثًا عن الصيغة اﻷفضل، وستختبر خطط تسعير مختلفة، وستصرف الكثير من الأموال على حملات Adwords بحثًا عن مواقع البيع الفريدة USP الخاصة بك. وأسوأ شيء يمكن توقعه بعد ذلك كله، هو أن لا يأتي هذا المجهود بأي نتيجة، فما من شيء يضمن أنّك ستسلك الطريقة المثلى للوصول إلى أفضل المبيعات. الخطأ اﻷول إذًا سيقضي على منتجك في مهده، إذ من السهل جدًّا أن تبني منتجًا عظيمًا لا يرغب به أحد، ذلك ﻷنّ مرحلة بناء المنتج ممتعة للغاية. لحسن الحظ هناك قاعدة بسيطة يمكن أن تجنّبك العمل لأيام أو أسابيع أو شهور دون الحصول على أي نتيجة. ضع خطّة لبيع المنتج قبل القيام بأي شيء آخر القاعدة هي أن لا تقوم بإنشاء المنتج قبل البحث عن طريقة لبيعه، وإنّما العكس تمامًا، فكّر في خطّة لبيع المنتج وتسويقه، ثم ابدأ بعدها بتطوير المنتج. اشرع بكتابة العبارات والنصوص التسويقية، وصمِّم العروض الترويجية والخطّة التسويقية، واعتن جيّدًا بالتفاصيل قبل أن تبدأ العمل ببناء المنتج. تحدّث عن المنتج أمام الآخرين، واكتب عنه في مدونتك، وفي حسابك على تويتر. ابدأ بتحضير صفحة الهبوط، واجمع عناوين بريد إلكتروني لمراسلة أصحابها حول المنتج. قد تبدو هذه الطريقة غير مريحة للأشخاص الذين يرغبون في الشروع ببناء المنتج على الفور، ولكن المغزى من هذه الطريقة هو أنّه إن لم تكن قادرًا على إقناع الناس بالعرض الذي ستقدّمه حول منتجك، فلن تكون قادرًا على إقناعهم بشراء المنتج إطلاقًا، وستغدو كل جهودك في تطوير المنتج هباءًا منثورًا. ولكن إن تمكنت من إثارة اهتمام الناس من خلال العرض الذي ستقدّمه عن المنتج فستكون حينها قد قطعت 75% من الطريق نحو تحقيق مبيعات ناجحة، وعندها فقط تستطيع البدء بكتابة شيفرات أو تصميم أو تأليف أو تسجيل المنتج الحقيقي. أدعو هذه الطريقة بالتطوير المستنِد إلى العرض التقديمي. التطوير المستنِد إلى العرض التقديمي يمنحك قوّة كبيرة يقدّم إليك التطوير المستنِد إلى العرض التقديمي إمكانية: التحدّث بوضوح حول المنتج (غير المنجز بعد) مع الجمهور أو باﻷحرى عملائك المحتملين. تجربة المنتج مجّانًا (من خلال صفحة تشويقية بعنوان (يأتيكم قريبًا…)). البدء بالتسويق بالمحتوى قبل إطلاق المنتج. الحصول على ثقة العملاء. تجربة أساليب مختلفة - توجهات، أنواع المنتج، طرق التوصيل، التوسع - لمعالجة المشاكل التي يواجهها الجمهور (وبدون تكاليف). استخدام العرض التقديمي الأفضل كمخطط تفصيلي لبناء المنتج، وحينها تكون جاهزًا للخوض في الجزء الممتع من الرحلة ألا وهو بناء المنتج. يقدّم لك العرض التقديمي الممتاز الثقة اللازمة ويوجّهك إلى الطريق الصحيح ويمنحك العديد من اﻷفكار ويمهّد الطريق لبناء المنتج، وإن لم يكن ذلك كلّه كافيًا فإنّه على اﻷقل سيوفّر عليك الكثير من الوقت والجهد والعناء. لست مضطرًّا لبيع المنتج مسبقًا للحصول على المال (وفي الواقع أنا لا أنصح بذلك، فقد تتسبّب الالتزامات الكثيرة بمشاكل كبيرة). يمكنك التنبّؤ برغبة جمهورك في دفع الأموال مقابل المنتج من خلال طرق أخرى كمشاركة المنتج في وسائل التواصل الاجتماعي أو من خلال إضافة عناوين البريد اﻹلكتروني إلى قائمتك البريدية. حاول أن تصل بعرضك التقديمي إلى مرحلة تدفع فيها جمهورك - عملائك المحتملين - إلى اتخاذ إجراء يبيّن مدى اهتمامهم بالمنتج، ذلك ﻷنّ الأفعال أصدق من الأقوال واﻷقوال أصدق من أفكارك ونظرياتك. خلاصة اﻷمر: لا ترتكب الخطأ اﻷول في بناء المنتج. لا تقضِ الأسابيع واﻷشهر في بناء منتجٍ لا تستطيع تسويقه وبيعه. لا تبنِ المنتج قبل أن تضع العرض التقديمي. ترجمة - وبتصرّف - للمقال The #1 mistake that’ll kill your product before you even start, AND how to avoid it entirely لصاحبته Amy Hoy. حقوق الصورة البارزة محفوظة لـ Freepik
  17. بما أنّ JSON مشتقة من لغة JavaScript البرمجية، فمن الطبيعي إذًا أن تُستخدم كتنسيق للبيانات في هذه اللغة. JSON هي اختصار لـ JavaScript Object Notation (تنويت كائنات JavaScript) وتلفظ غالبًا كما يلفظ اسم (Jason). يمكن استخدام JSON في: تخزين البيانات. إنشاء بنى المعلومات من خلال المعلومات التي يدخلها المستخدم. نقل البيانات من الخادوم إلى العميل، ومن العميل إلى الخادوم، ومن العميل إلى العميل. ترتيب البيانات والتحقق منها. يمثّل هذا المقال مقدّمة للعمل على JSON من خلال لغة JavaScript، ويجب أن تكون مطّلعًا على هذه اللغة لتحصل على الفائدة المرجوة من المقال. صيغة JSON صيغة JSON مشتقة من صيغة الكائنات في JavaScript، ولكنّها صيغة نصّية بالكامل، وهي عبارة عن أزواج من المفاتيح والقيم التي تحاط عادة بأقواس معقوفة. عادة ما تخزّن كائنات JSON في ملف بامتداد .json ولكن يمكن أن تجد هذه الكائنات ضمن سياق البرنامج. تكون ملفات .json بالصيغة التالية: { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } إما إن كانت كائنات JSON موجودة في ملف بامتداد .js أو .html فستكون على اﻷغلب مسندة إلى متغير وبالصورة التالية: var sammy = { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } إضافة إلى ذلك، يمكن أن ترى JSON على هيئة سلسلة نصية لا عنصر وذلك ضمن شيفرة JavaScript، ويمكن كتابة الصيغة في سطر واحد كما يلي: var sammy = '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}'; تحويل كائنات JSON إلى سلاسل نصّية مفيد في نقل البيانات بصورة سريعة. مقارنة JSON مع كائنات JavaScript من المهمّ جدًّا الانتباه إلى أنّ JSON قد طُوّرت لكي تستخدم من قبل أي لغة برمجية، في حين أن التعامل مع كائنات JavaScript يكون بواسطة هذه اللغة حصرًا. أما بالنسبة إلى الصياغة، فإن كائنات JavaScript مشابهة لـ JSON، ولكن الفرق هو أنّ المفاتيح في كائنات JavaScript ليست سلاسل نصّية ضمن علامات اقتباس، إضافة إلى أنّه يمكن استخدام الدوال كقيم في هذه الكائنات. لنأخذ المثال التالي لكائن JavaScript الخاص بالمستخدم Sammy Shark والمتّصل حاليًا بالإنترنت: var user = { first_name: "Sammy", last_name : "Shark", online : true, full_name : function() { return this.first_name + " " + this.last_name; } }; من الواضح جدًّا أن هذا الكائن مشابه جدًّا لكائن JSON، ولكن لا وجود لعلامات الاقتباس حول أيٍّ من المفاتيح (first_name, last_name, online, أو full_name)، إضافة إلى أنّ قيمة المفتاح الأخير عبارة عن دالّة. يمكن استخدام التنويت النقطي للوصول إلى البيانات الموجودة في كائن JavaScript السابق، فلاستدعاء قيمة الاسم الأول نستخدم الصيغة: user.first_name وسنحصل على سلسلة نصّية، أما لو أردنا الوصول إلى الاسم الكامل، ونظرًا لكون القيمة دالّة، فستكون صيغة الاستدعاء بالصورة التالية: user.full_name(). كائنات JavaScript موجودة فقط ضمن هذه اللغة، لذا إن كنت بحاجة للوصول إلى البيانات عن طريق لغات برمجية أخرى، فعليك حينئذ استخدام JSON لتخزين البيانات. الوصول إلى بيانات JSON يمكن الوصول إلى بيانات JSON بنفس الطريقة المتّبعة في كائنات JavaScript، ولتوضيح ذلك لاحظ المثال التالي: var sammy = { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } لتتمكن من الوصول إلى أيّ من القيم السابقة يمكن استخدام التنويت النقطي بالصورة التالية: sammy.first_name sammy.last_name sammy.online يأتي اسم المتغير sammy في البداية متبوعًا بنقطة متبوعة بالمفتاح الذي ترغب في الوصول إليه. فمثلًا، لإطلاق مربع تنبيه يعرض القيمة المرتبطة بالمفتاح first_name يمكن استدعاء دالّة alert() في JavaScript بالشكل التالي: alert(sammy.first_name); Output Sammy كذلك يمكن استخدام الأقواس المربعة [] للوصول إلى البيانات في JSON، وذلك بكتابة اسم المفتاح ضمن علامتي اقتباس محاطًا بقوسين مربعين. فيصبح المثال السابق بالشكل التالي: alert(sammy["online"]); Output true وفي حال استخدام المصفوفات المتشعبة Nested Arrays يجب حينئذ استدعاء رقم العنصر ضمن المصفوفة. لنأخذ المثال التالي: var user_profile = { "username" : "SammyShark", "social_media" : [ { "description" : "twitter", "link" : "https://twitter.com/digitalocean" }, { "description" : "facebook", "link" : "https://www.facebook.com/DigitalOceanCloudHosting" }, { "description" : "github", "link" : "https://github.com/digitalocean" } ] } لتتمكن من الوصول إلى السلسلة النصية facebook يجب عليك استدعاء العنصر ضمن المصفوفة مع استخدام النقطة وبالصورة التالية: alert(user_profile.social_media[1].description); Output facebook لاحظ أنّنا نستخدم نقطة إضافية للوصول إلى العنصر المتشعّب ضمن المصفوفة. بعض الدوال التي تساعد في التعامل مع JSON سنستعرض دالّتين مهمّتين في التعامل مع بيانات JSON، الأولى تعمل على تحويل البيانات إلى سلاسل نصية والأخرى تقوم بتحليلها. إن إمكانية تحويل JSON من كائن إلى سلسلة نصّية مفيد جدًّا في تحويل البيانات وتخزينها. JSON.stringify() تحوّل هذه الدالة الكائن إلى سلسلة JSON نصية. يمكن الاستفادة من السلاسل النصّية لتحويل البيانات من العميل إلى الخادوم وذلك من خلال خزن المعلومات أو تمريرها بصورة سهلة وسريعة. فعلى سبيل المثال، يمكنك مثلًا الحصول على الإعدادات الخاصّة بالمستخدم من طرف العميل ثم إرسالها إلى الخادوم، وفي وقت لاحق يمكنك قراءة تلك المعلومات وتحليلها بواسطة دالّة JSON.parse() واستخدام البيانات حسب الحاجة. في المثال التالي نسند كائن JSON إلى المتغير obj، ثم نحوّله إلى سلسلة نصية من خلال تمريره إلى الدالة JSON.stringify() وإسناد القيمة إلى المتغيّر s: var obj = {"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"} var s = JSON.stringify(obj) والآن يمكن التعامل مع المتغيّر s والذي يضمّ معلومات JSON على هيئة سلسلة نصّية. '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}' JSON.parse() قلنا أنّ السلاسل النصية مفيدة في نقل المعلومات، ولكن يجب أن تتوفّر إمكانية تحويل هذه السلاسل مرّة أخرى إلى كائنات JSON سواء من طرف العميل أو الخادوم. يمكن تحويل السلال النصّية إلى كائنات باستخدام الدالة eval() ولكن هذه الطريقة غير آمنة، لذا سنستخدم الدالة JSON.parse() بدلًا عنها. لتحويل السلسلة النصّية في المثال السابق إلى كائن JSON نقوم بتمرير المتغيّر s إلى الدالّة وإسناد القيمة المستحصلة إلى متغيّر جديد: var o = JSON.parse(s) أصبح لدينا الآن الكائن o وهو مطابق تمامًا للعنصر obj. لتوضيح الفكرة بشكل أكبر سنأخذ المثال التالي والذي نستخدم فيه دالة JSON.parse() في ملف HMTL. <p id="user">Name: Sammy Shark<br>Location: Ocean</p> <script> var s = '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}'; var obj = JSON.parse(s); document.getElementById("user").innerHTML = "Name: " + obj.first_name + " " + obj.last_name + "<br>" + "Location: " + obj.location; </script> Output Name: Sammy Shark Location: Ocean لاحظ كيف حوّلنا السلسلة النصّية s إلى كائن JSON يمكن استدعاء القيم التي يتضمّنها وتصييرها على صفحة الإنترنت. الخلاصة JSON هي الصيغة الافتراضية التي تستخدم في JavaScript ويمكن تضمين هذه الصيغة في العديد من اللغات البرمجية الشائعة. ويمكنك الاطلاع على اللغات التي تدعم هذه الصيغة من خلال الموقع الإلكتروني الخاص بهذه الصيغة. ونظرًا لصغر حجم JSON وسهولة نقل المعلومات بين لغات البرمجة والأنظمة المختلفة، تستخدم هذه الصيغة بصورة واسعة في الواجهات البرمجية APIs، مثل واجهة Twitter البرمجية. تجدر الإشارة إلى أنّك لن تنشئ ملفات .json بنفسك على الأغلب بل ستحصل عليها من مصادر أخرى، مثل ملفات CSV التي تستخدم لتخزين البيانات المجدولة، أو ملفات XML أو غيرها. وسواء أكتبت JSON بنفسك أو حصلت عليها من مصدر آخر، يمكن التأكد من صحّة الصيغة التي كتبتها باستخدام الأداة JSONLint. ترجمة - وبتصرّف - للمقال How To Work with JSON in JavaScript لصاحبته Lisa Tagliaferri.
  18. أنت تتعرض للتقييم في كلّ مرة تقابل فيها شخصًا ما سواء أأدركت ذلك أم لا، ولا أقصد هنا تقييم أعمالك وتصاميمك وبرامجك التي تطوّرها، مع أن هذا النوع من التقييم مهمّ بكل تأكيد. ما أعنيه هو تقييم شخصيتك ومواقفك وأسلوبك في الكلام وهندامك ومظهرك الخارجي، فهذه الأمور هي أوّل ما يراه الأشخاص الذين تقابلهم وتكوّن علاقات معهم، وهذا الأمر مفصليّ بالنسبة للمستقلّ الذي يسعى إلى توسيع قاعدة عملائه. في هذا المقال سنتطرق إلى بعض الطرق التي تساعد في تحسين سمعتك كمستقلّ، الأمر الذي سيؤدّي إلى تعزيز سيرتك المهنيّة بصورة كبيرة. كل الأشخاص نقّاد نحن ننتقد كلّ ما يصادفنا وكلّ من نلتقي به وبصورة يومية، وعندما تلتقي بعميلك المحتمل فإنّك ستقرّر - دون أن تشعر - ما إذا كنت ستوافق على العمل معه أم لا. يقال أنّ الانطباع الأوّلي يدوم إلى الأبد؛ وانطلاقًا من هذه المقولة عليك أن تسعى جاهدًا لرسم صورة مشرّفة عندما تقدّم نفسك أو عملك لعميل محتمل. ويمكن القول أنّ أسلوب التواصل مع الآخرين هو أحد أهم الوسائل التي تساعد في عرض جوانبك الجيّدة للعملاء المحتملين. أذكر أنّي تعاملت مع مصمّمة لمجرد أنّي سمعت - وعن طريق الصدفة - أسلوبها في التخاطب مع الآخرين. لقد كانت مهذّبة وصادقة ومفعمة بالثقة، وكانت تتمتّع بمهارات تواصل مذهلة انعكست بصورة جليّة على مظهرها وأسلوبها في الكلام. وكان انطباعي الأوّل عنها: “تعرف هذه المرأة ما تقوم به جيّدًا، وإن عملت معها فسأكون مطمئنًّا إلى أنّها ستنجز العمل على أتمّ وجه”. يجب عليك كمستقلّ أن تبذل قصارى جهدك لتمنح الآخرين مثل هذا الانطباع، فلربّما ينظر إليك عميلك الكبير القادم دون أن تشعر بذلك. مكوّنات السمعة الجيدة هناك ثلاثة أمور أساسية يجب تحقيقها لبناء سمعة مهنية جيّدة: أن تكون محبوبًا. أن تكون محلًّا للثقة. أن تكون محترمًا. تستند السمعة المهنيّة الممتازة على هذه الركائز الثلاثة، ولا غنى لك عن أي واحدة منها، فحبّ الناس لك يعني أنّك أهلٌ للثقة، فما من أحد يثق بمن لا يحبّ، وبمجرّد أن تنال ثقة الناس فإنّك ستكون قادرًا على كسب احترامهم. يجب عليك كمصمّم أن تتحلّى بسلوك يبعث على الثقة والإعجاب لتكون قادرًا على تجاوز منافسيك والوصول إلى نوعية العملاء الذين ترغب حقًّا في التعامل معهم. قد يكون هذا الأمر صعبًا في البداية، خصوصًا إن كنت من الذين يشعرون براحة أكبر عند الجلوس أمام الحاسوب ولا يحبّذون الاختلاط مع الناس، ولكن الخطوة الأولى تتلخّص في تغيير الصورة التي يراك الناس بها. قد لا تحصل على نتيجة مثالية في بداية الأمر، ولكن مع الملاحظة والتمرين المستمرّين، ستكون قادرًا على نيل محبّة الناس وثقتهم بك في وقت قصير جدًّا. اسأل واستمع قد تتسائل: “هذا رائع جدًّا، ولكن كيف يكون بميسوري تغيير صورتي أمام الآخرين؟”. لا أدّعي أن هذا الأمر سيكون سهلًا، ولكن يمكنك اتباع بعض الخطط والأساليب التي ستساعدك على تحسين صورتك وسمعتك أمام الناس. اطلب من معارفك أن يقدّموا رأيهم فيك عندما يقابلونك وبكلّ صراحة، واستمع إلى ما يقولون بانتباه شديد وصدر رحب. هل يشعر المقرّبون منك أنّك شخص لحوح؟ هل يرون أنّك تقاطع الآخرين كثيرًا أثناء المحادثة؟ أتبدو في نظرهم شخصًا متكبّرًا للغاية أم خجولًا جدًّا أم غريب الأطوار؟ يرتكب جميع البشر الأخطاء، ولكن الاستماع إلى النقد الصادق وتحمّله هو الوسيلة الوحيدة لتجاوز هذه الأخطاء، وبطبيعة الحال، لن تكون قادرًا على تجاوز المشكلة ما لم تعي وجودها. من الطرق النافعة كذلك فيما يتعلّق بهيأتك ومهارات التواصل الاجتماعي، هي التدرّب على هذه الأمور أمام الكاميرا وليس المرآة، إذ من الضروري أن تسجّل حديثك وطريقتك في الإجابة على الأسئلة… الخ لتتمكّن من تشخيص نقاط الضعف ومن ثمّ معالجتها. يمكن لبضع ساعات من التدريب أن تحسّن مهارات التواصل لديك بصورة كبيرة جدًّا، وقد تتسبّب مراجعة التسجيلات في بعض الإحراج، لكنّ أداءك سيتحسّن بسرعة كبيرة. لا تغفل عن هدفك الأساسي يتطلب بناء السمعة الحسنة الكثير من الوقت والجهد، لذا احرص على أن تعالج أخطاءك قبل أن تتسبّب في مشاكل دائمية لا يمكن حلّها، فهناك حدّ معين يصبح من المستحيل بعده إرجاع الأمور إلى نصابها. والمشاهير هم خير دليل على ذلك، والفرص المتاحة أمام هؤلاء الأشخاص تفوق الفرص المتاحة أمام بقية الناس، ولكن من المؤكّد أنّك سمعت بأن أحد المشاهير قد ارتكب فعلًا مشينًا أطاح بسمعته إلى درجة يستحيل أن تعود بعدها إلى سابق عهدها. لا يدرك هؤلاء الأشخاص - في معظم الأحيان - أنّ لأفعالهم أثرًا بالغًا في سمعتهم وبنظرة الناس إليهم، وأنّ السيرة المهنيّة للمشاهير تحت رحمة الرأي العام، ومن اليسير أن تصبح الثروة والشهرة سببًا في ارتكاب أخطاء تودي بالمرء إلى الهاوية. الحفاظ على السمعة الحسنة إن الحفاظ على السمعة الحسنة يتطلّب منك الانتباه واليقظة الدائمين، وأهمّ وسيلة لإحراز التقدّم والحصول على العملاء وتوسيع علاقاتك الاجتماعية هي أن تكون محبوبًا لدى الناس، وبميسورك أن تكون مستعدًّا لمواجهة أيّة مشكلة قد تؤثّر سلبًا على سمعتك وذلك بالتفكير الدائم في الصورة التي ترغب في عكسها للناس. استمرّ في وضع الأهداف لنفسك واسع لتحقيقها على الدوام، وطوّر شخصيتك وأسلوبك، وابحث دائمًا عن النقد البنّاء وضع لنفسك خطّة منظّمة لتغيير سلوكك لتبني الصورة التي ترغب أن يراك الناس فيها. ترجمة - وبتصرّف - للمقال The Importance of Your Reputation as a Freelance Creative لصاحبته Addison Duvall. حقوق الصورة البارزة محفوظة لـ Freepik
  19. ﻻ بد أن تمرّ الشركة الناشئة - مهما كانت طبيعة فريق العمل - بمرحلة الوقوع في مشاكل لا تستطيع الخروج منها. والتحدّي الحقيقي - والحال هذه - هو تحديد الوقت اللازم لحلّ المشاكل التي تواجه الشركة، فهل ينبغي متابعة المشكلة والعمل على حلّها بشكل كامل مهما استغرق ذلك من وقت، أم يجدر طلب المساعدة عند العجز عن إيجاد الحلّ المناسب؟ تساعد قاعدة الـ 15 دقيقة كل فرد من أعضاء فريقك على إدراك القيمة الحقيقية لمفهوم الاكتفاء الذاتي، وتلزمهم في الوقت عينه بأن يلجأوا إلى أطواق النجاة عندما تقتضي الحاجة ذلك. تعلّمت هذه القاعدة البسيطة من Jeff مدير فريق دعم العملاء في شركتنا عندما كنت مهندسًا في هذا القسم. طلب مني Jeff في حال واجهتني مشكلة مع أحد العملاء أن أبحث بنفسي عن حلّ لها لمدة 15 دقيقة، وإن عجزت عن إيجاد الحلّ خلال هذه الفترة أتوجّه حينئذٍ إليه طلبًا للمساعدة. قاعدة الـ 15 دقيقة حاول أن تجد بنفسك حلًّا للمشكلة التي تواجهك ولمدة 15 دقيقة، وإن عجزت بعد هذه الفترة عن إيجاد الحل توجّه إلى شخص آخر طلبًا للمساعدة. يجب عليك إيجاد الحل بنفسك لم تكن غاية Jeff من هذه القاعدة الامتناع عن مساعدتي، بل العكس تماماً، فلو رميت جميع المشاكل التي تواجهني على اﻵخرين دون فهم أسبابها، لن أكون قادرًا حينها على حلّ أي مشكلة بمفردي. تعلّمك الدقائق الخمس عشرة مهارة مهمّة في مجال دعم العملاء، ألا وهي معرفة ما يجب عليك البحث عنه وكيفية إجراء البحث بصورة صحيحة. يجب على كلّ موظف في قسم دعم العملاء أو الفريق الهندسي أن يكون قادرًا على التنقل ضمن الأكواد الأساسية والتوثيقات، ويجب أن يدرك بأنّ الحلّ موجود لو أنّه أخذ الوقت الكافي للبحث عنه. إضافة إلى ما سبق، فإنّ هذه الدقائق الخمس عشرة ستجعلك على اطلاع جيّد بحيثيات المشكلة، ذلك لأنّك قد بحثت خلال هذه الفترة في الأكواد الأساسية، واطلعت على المحادثات السابقة، وفتّشت في محادثات Slack، وتفحّصت التوثيقات الداخلية، ورغم ذلك كله لم تفلح في الوصول إلى الحلّ. ولكن يمكن أن تكون المعلومات التي حصلت عليها في أغلب الأحيان معلومات مهمّة وقيّمة للشخص الذي ستطلب مساعدته، وقد يعينكما ذلك على حلّ المشكلة بسرعة أكبر. ولكن ينبغي عليك طلب المساعدة في بعض اﻷحيان لن تسعفك الدقائق الخمس عشرة في إيجاد الحلّ لمشكلة معينة، وقد لا يسعفك البحث ليوم كامل كذلك. في مثل هذه الحالات، ستجبرك القاعدة على طلب المساعدة. من اليسير جدًّا أن تنغمس إلى أذنيك في حلّ المشكلة، ولكن ينبغي عليك أن تسأل نفسك حينها: “أأنا الشخص المناسب لحلّ هذه المشكلة؟”. يقول المثل: الوقت كالسيف إن لم تقطعه قطعك. قد تشعر بالرضا والفخر بعد أن تبذل مجهودًا كبيرًا في تعلّم أمور جديدة - وستحصل على خبرة كبيرة على المدى الطويل - ولكن لا تتوقع مطلقًا أن تنال الثناء على قضاء ساعات في حلّ مشكلة يمكن لغيرك أن يحلّها في عشر دقائق. كيف يمكن لقاعدة الـ 15 دقيقة أن تساعد الفريق برمّته تقدّم قاعدة الدقائق الخمس عشرة لفرق دعم العملاء أو الفرق الهندسية أو غيرها فوائد جمّة: يتعلّم الموظفون الجدد الاعتماد على أنفسهم. هناك من يستطيع الموظف الجديد الاستعانة به عندما لا يجدّ حلًّا للمشكلة التي يحاول معالجتها. يمكن لهؤلاء الموظفين أن يستشيروا الموظفين القدماء ليتعرفوا على اﻷسلوب الذي يتبعونه في حل المشكلات. يراجع الموظفون القدماء بصورة غير رسمية عمل الفريق ويقدّمون تغذيتهم الراجعة. تزداد خبرة فريق دعم العملاء دون أن يضطر العملاء إلى الانتظار لفترات طويلة للحصول على اﻹجابات. على الرغم من أني لم أعد أعمل مهندسًا (كما أني لست مطّلعًا على جميع التوثيقات)، إلا أنّي ألجأ بصورة منتظمة إلى قاعدة الدقائق الخمس عشرة، فهي تعلّمني احترام وقت زملائي، وتشجّعني في الوقت ذاته على طلب المساعدة عندما أكون محتاجًا إليها. لذا أدعوك لأنّ تجرّب هذه القاعدة وأن تشاركنا النتائج في التعليقات. ترجمة - وبتصرّف - للمقال Know when to ask for help with the 15 Minute Rule لصاحبه Martin Brennan. حقوق الصورة البارزة محفوظة لـ Freepik
  20. إنّ مطالعتك لهذا المقال يعني على الأرجح أنّك قد أتممت الخطوة الأولى في رحلتك كمستقلّ يعمل على شبكة الإنترنت، ألا وهي إيجاد العملاء. وكم نتمنى أن تكون الرحلة قد انتهت عند هذه النقطة، ولكن يؤسفني القول أنّك لا زلت بعيدًا جدًّا عن نقطة النهاية حتى بعد العثور على شخص يرغب في دفع المال لقاء الخدمات التي تقدّمها. بل يمكن القول أنّك الآن تخوض الجزء الأصعب من الرحلة، إذ يجب عليك التعامل مع العملاء مع الحرص على: أن يكون عملاؤك سعداء. أنا لا تصاب بالجنون (وهذه هو الأهمّ، رغم أنّنا ننسى ذلك بعض الأحيان). التعامل مع العملاء أشبه ما يكون بسير البهلوان على الحبل، فمن جانب ترغب في إسعاد عملائك مهما كلّف ذلك، ومن جانب آخر، لا ترغب في أن يتّصل بك العميل عبر Skype في الساعة العاشرة مساءً ليلة السبت، أليس كذلك؟ لا أنكر وجود عملاء جيّدين يحترمون الوقت ويكون التعامل معهم سهلًا ومريحًا، ولكن هناك عملاء متطلّبون للغاية، ويدفعونك إلى اقتلاع شعر رأسك، وأنا متأكد من أنّ لدى كلّ منا العديد من القصص والتجارب التي يمكن أن يرويها في هذا الصدد. في هذا المقال سأتحدّث عن كيفية إدارة علاقاتك مع عملائك بصورة أفضل ومن جانبين مختلفين. وستكون قادرًا بعد الانتهاء من مطالعة المقال على إسعاد عملائك دون التفريط بسعادتك الشخصية. كيف تحافظ على سعادة عملائك إن عدم وجود عملاء سعداء يعني أنّك لن تحصل على لقمة العيش، وهذا ليس أمرًا جيّدًا بحدّ ذاته. لذا إليك بعض النصائح - غير تلك النصائح الواضحة مثل إنجاز الأعمال بجودة عالية واحترافية كبيرة - التي تساعدك في المحافظة على سعادة عملائك: أرسل مستجدّات المشروع بصورة استباقية لقد وجدت خلال مسيرتي المهنيّة كمستقلّ أنّ إرسال رسائل إلكترونية استباقية إلى العميل بخصوص مستجدّات المشروع أمرٌ مفيدٌ للغاية. وأعني بالرسائل الاستباقية، رسائل سريعة مثل: “أود إعلامك بأني قد أكملت الخطوة س من المشروع وسأرسلها إليك في الموعد ص كما هو مقرّر”. إن كنت قد وضعت موعدًا لإنجاز العمل، فإن العميل سيتوقع منك إتمام العمل في ذلك الموعد، ولكن عندما لا يكون العمل وجهًا لوجه، سيشعر العميل بعدم الراحة والخوف من عدم الالتزام بموعد اﻹنجاز المحدّد. تساعد هذه الرسائل القصيرة على معالجة المشكلة قبل أن تكبر وتتفاقم، وﻻ يتطلّب كتابة مثل هذه الرسائل أكثر من دقيقة واحدة، لذا لا تسمح للشكّ بأن يتسلّل إلى عميلك، بل أطلعه على المستجدّات أوّلًا بأوّل، وأعدك بأنّه سيقدّر ذلك كثيرًا. اخفض سقف الوعود وارفع سقف الإنجازات إن كنت تعتقد بأنّك ستنجز العمل خلال 7 أيام فلا تخبر العميل بذلك على الإطلاق، بل أخبره بأنّك ستنجز العمل خلال 10 أيام. بل الأفضل أن تكون المدّة 14 يومًا. وستنجز بذلك أمرين اثنين: إن كان اعتقادك صحيحًا، فستبدو في نظر عميلك بطلًا خارقًا استطاع إنجاز المشروع في وقت مبكّر. إن كنت مخطئًا في اعتقاد، فسيكون لديك الوقت الكافي لإنجاز المشروع وأنت مرتاح البال. أنجز أكثر مما هو مطلوب منك لا أقصد هنا العمل الإضافي دون مقابل، بل ما أعنيه أنّك على دراية كبيرة بالإنترنت، وهذا يعني أنّك على الأرجح تمتلك معلومات أكثر من عميلك، وبإمكانك الاستفادة من هذه المعلومات في إسعاد العميل. لتقريب المعنى إليك المثال التالي: حتى لو لم تكن خبيرًا في SEO فإنّ معلوماتك حول هذا الموضوع ستفوق على الأرجح معلومات عميلك؛ لذا إن لاحظت وجود مشكلة كبيرة في SEO أثناء القيام بعملك الاعتيادي، لا تتردّد في إطلاع عميلك على المشكلة. لن يكلّفك الأمر سوى رسالة إلكترونية واحدة، أو يمكنك الحديث عن الموضوع خلال مكالمة هاتفية مع العميل، ولكن بالنسبة إلى العميل فسيبدو الأمر وكأنّك تحرص على أن يحقق العميل النجاح مهما كلّفك ذلك. عادة ما يُسعد العملاء بمثل هذه الملاحظات، وستغدو بالنسبة إلى عميلك مستشارًا أكثر من كونك مجرّد منفّذ للعمل. أنا أقدّم لعملائي النصائح والآراء وبصورة دائمة في أمور لا ترتبط بالكتابة، وحسب تجربتي الشخصية، فإن الغالبية العظمى من العملاء يقدّرون هذه المساعدة. احرص فقط على أن تكون منطقيًّا هنا، فإن لم يتجاوب العميل مع اقتراحات ونصائحك منذ البداية فعليك صرف النظر عن الموضوع تمامًا. كيف تحافظ على سلامتك إن كانت طريقتك الوحيدة في إسعاد عملائك تتمثّل في التواصل معهم طوال اليوم وعلى مدار الأسبوع عبر جميع وسائل التواصل المتاحة فستصاب باﻹعياء. قد لا يحدث هذا بادئ الأمر، ولكنّي أعدك أنّه سيحدث حتمًا. تجنّب إذًا الوقوع في هذا الفخّ باتباع النصائح التالية، وإن وضّحت الأمور لعملائك منذ البداية فلن تتأثر علاقتك بهم على الإطلاق وستشعر براحة وسعادة كبيرتين. اجعل عدد قنوات التواصل محدودًا أذكر أن صفحة “تواصل معي” في أيامي الأولى كمستقل كانت تتضمّن استمارة التواصل، وعنوان بريدي الإلكتروني، وحساباتي في Skype وTwitter وإحداثيات GPS الخاصة بي ليتواصل العملاء معي بواسطة الحمام الزاجل… هل فهمت ما أقصد؟ كنت أفكّر أنّني سأكون متوفّرًا للعملاء في أي وقت، وهكذا سيحبّونني بالتأكيد، ولم أشكّ للحظة في مدى صحّة هذه الفكرة، إلى أن وصلتني أول رسالة على Skype في ليلة السبت، أعقبتها رسالة أخرى بعد عشر دقائق لأنني لم أردّ على الرسالة اﻷولى. أما اليوم فصفحة “تواصل معي” تتضمن استمارة وحيدة فريدة: ضع الصورة نعم، هذه هي وسيلة التواصل الوحيدة. أسعى من خلال هذه الاستمارة إلى أن أقلّص قدر الإمكان قنوات التواصل إلى نطاق البريد الإلكتروني أو Trello. لا مشكلة على الإطلاق في أن تستخدم طرق تواصل مختلفة، ولكن وبحسب خبرتي في هذا المجال يفضّل أن تتبع هاتين القاعدتين: اختر وسيلة التواصل المفضّلة لديك والتزم بها، فإن كنت تحبّ Skype وجّه كل عمليات التواصل باتجاهه والتزم بذلك. افصل وسيلة التواصل هذه عن حساباتك الشخصية. فعلى سبيل المثال، لو كنت تملك حسابًا على Skype تتواصل من خلاله معه الأهل والأصدقاء، أنشئ حسابًا آخر مخصّصًا للعمل. بهذه الطريقة، لن تقع تحت وابل من رسائل العمل لمجرد أنّك ترغب في التواصل مع عائلتك في عطلة نهاية الأسبوع (هذا ما حدث معي في بداياتي كمستقلّ). الفائدة الثالثة هي أنّ الالتزام بوسيلة تواصل محدّدة يسهّل عليك الرجوع إلى المحادثات السابقة في حال نسيت بعض التفاصيل المتعلّقة بالمشروع. حدّد المدّة المتوقّعة للاستجابة بعد أن أزلتُ جميع وسائل التواصل الزائدة من صفحة “تواصل معي”، أضفت رسالة تظهر مباشرة بعد أن يقوم العميل بتعبئة الاستمارة وإرسالها. مضمون الرسالة هو: “شكرًا على تواصلك معي. سأجيبك خلال الـ 24 ساعة القادمة باستثناء عطلة نهاية الأسبوع”. ضع الصورة ستتعب كثيرًا إن حاولت البقاء على تواصل مع عملائك طوال اليوم، وهذا أمر لا شكّ فيه، ولكن سيتوقع الكثير من العملاء أنّك ستجيب على رسائلهم في أوقات غريبة من اليوم، إلا إذا بيّنت لهم ومنذ البداية الوقت المتوقّع للتواصل. لذا، حدّد الفترة التي تناسبك للتواصل مع العملاء ثم بيّن ذلك لهم منذ البداية. لا أذكر أنّ أحد من العملاء قد رفض الانتظار لمدة 24 ساعة ليحصل على الإجابة ما دمت قد بيّنت له ذلك منذ البداية. مع ذلك يجب عليك الاستجابة لرسائل العميل بالسرعة الممكنة، إذ سيشعر العميل بقليل من الاستياء إن أصبحت مدة الاستجابة لديك 24 ساعة بعد أن كانت ساعتين فقط. كن منظّمًا الطريقة الأخيرة للمحافظة على سلامتك هي اعتماد طريقة عمل منظّمة وتطبيقها مع جميع العملاء. وأفضل طريقة للاطلاع الكامل على ما يدور بينك وبين عميلك هو الاحتفاظ بجميع مواعيد الإنجاز واللقاءات في مكان واحد. لا أحبّذ هنا تفضيل طريقة على أخرى، إذ يبدو أنّ لكل شخص ما طريقته المفضّلة. أنا أستخدم [Todoist](Keep Yourself Sane)، ولكني أعرف الكثير من الأشخاص الذي يفضّلون استخدام أدوات ذات مزايا أكبر لإدارة المشاريع مثل: Asana Basecamp Trello ليس المهمّ الاعتماد على منصّة معينة، بل المهمّ أنّك تستخدم إحدى الأدوات لإدارة مشاريعك وسير عملك، فسرعان ما تقع تحت ضغط عمل شديد ما إن تتذكّر موعد إنجاز مشروع كنت قد نسيته تمامًا. الخلاصة إضافة إلى كل ما ورد أعلاه، أرجو منك أن تتّبع أساسيات النجاح في إدارة علاقاتك مع العملاء: اطلب عقدًا موقّعًا في حال عملك على مشاريع كبيرة. ناقش بوضوح مدى قدرتك على إنجاز العمل. احرص على تقديم عمل جيد. سيساعدك اتباع هذه الأساسيات في إسعاد عملائك دون التفريط بسعادتك وصحّتك وحياتك الشخصية. إن كنت تملك نصائح أخرى لإدارة العلاقة مع العملاء فلا تبخل بها علينا؛ فإضافة إلى تقديم المساعدة لكلّ من يقرأ هذا المقال، أحبّ دومًا أن أنظّم أساليبي الخاصة في العمل. ترجمة - وبتصرّف - للمقال Managing Clients: How to Keep Them Happy Without Pulling Your Hair Out لصاحبه Colin Newcomer. حقوق الصورة البارزة محفوظة لـ Freepik
  21. هذا هو الجزء الأخير من سلسلة “مدخل إلى إطار العمل Ruby on Rails” وفي هذا الجزء سنعيد هيكلة الشيفرة التي كتبناها في الأجزاء السابقة من السلسلة، وسنتعرّف إلى نظام الاستيثاق البسيط الذي يقدّمه إطار العمل Rails. إعادة هيكلة الشيفرة بعد أن أصبحت المقالات والتعليقات تعمل بصورة جيدة، لنلقِ نظرة على القالب app/views/articles/show.html.erb . يبدو الملف طويلًا جدًّا، لذا سنستخدم الملفات الجزئية لتنظيف وترتيب الشيفرة البرمجية. تصيير مجموعة الملفات الجزئية في البداية سننشئ ملفًّا جزئيًا خاصًّا بالتعليقات وظيفته عرض جميع التعليقات الخاصّة بالمقالة. أنشئ الملف app/views/comments/_comment.html.erb وأضف إليه الشيفرة التالية: <p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> والآن يمكنك تعديل الملف `app/views/articles/show.html.erb` كما يلي: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <%= render @article.comments %> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> بهذه الطريقة سيتم تصيير الملف الجزئي في app/views/comments/_comment.html.erb لكلّ تعليق موجود في مجموعة @article.comments، وعندما يتنقّل التابع render بين عناصر مجموعة التعليقات فإنه يُسند كل تعليق إلى متغيّر محلي local variable يحمل اسم الملف الجزئي ذاته، وفي حالتنا هذه comment والذي يكون متوفّرًا في الملف الجزئي. تصيير الملف الجزئي الخاصّ بالاستمارة لنقم بإزالة قسم التعليقات الجديد إلى ملف جزئي خاصّ به، ومرة أخرى أنشئ ملفًّا باسم _form.html.erb في المجلد app/views/comments/ وأضف إليه ما يلي: <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> ثم عدّل الملف app/views/articles/show.html.erb ليصبح بالصورة التالية: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <%= render @article.comments %> <h2>Add a comment:</h2> <%= render 'comments/form' %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> يعرّف تابع render الثاني القالب الجزئي الذي نرغب في تصييره وهو comments/form، ونظرًا لوجود المحرّف / ضمن هذه السلسلة النصّية سيعرف Rails بأنّك ترغب في تصيير الملف _form.html.erb الموجود في المجلد app/views/comments. أما الكائن @article فسيكون متوفّرًا لأيّ ملفّ جزئي يتم تصييره في العرض لأنّنا عرّفناه كمتغيّر من نوع instance. حذف التعليقات إن القدرة على حذف التعليقات المزعجة هي من الميزات المطلوب توفرها في المدوّنة، ولتنفيذ ذلك سنحتاج إلى إضافة رابط لحذف التعليقات ضمن العرض وإلى حدث destroy في المتحكّم CommentsController. لذا سنضيف أوّلًا رابط الحذف ضمن الملفّ الجزئي app/views/comments/_comment.html.erb وكما يلي: <p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> <p> <%= link_to 'Destroy Comment', [comment.article, comment], method: :delete, data: { confirm: 'Are you sure?' } %> </p> سيؤدّي النقر على هذا الرابط إلى إرسال الفعل DELETE متمثّلًا بالرابط /articles/:article_id/comments/:id إلى المتحكّم CommentsController، والذي سيبحث بدوره - مستعينًا بهذا الرابط - عن التعليق المراد حذفه من قاعدة البيانات. لنضِف حدث destroy إلى المتحكّم في الملف app/controllers/comments_controller.rb: class CommentsController < ApplicationController def create @article = Article.find(params[:article_id]) @comment = @article.comments.create(comment_params) redirect_to article_path(@article) end def destroy @article = Article.find(params[:article_id]) @comment = @article.comments.find(params[:id]) @comment.destroy redirect_to article_path(@article) end private def comment_params params.require(:comment).permit(:commenter, :body) end end سيبحث الحدث destroy عن التعليق المراد حذفه، ثم يعيّن موقعه في مجموعة @article.comments ثم يحذفه من قاعدة البيانات ويعيد توجيهنا إلى حدث show الخاصّ بالمقالة. حذف الكائنات المترابطة من البديهي أنّه عند حذف مقالة معيّنة فإن من الواجب أن يتم حذف التعليقات المرتبطة بها، وإلا فستشغل هذه التعليقات مساحة ضمن قاعدة البيانات دون أيّ فائدة. يتيح لنا Rails استخدام الخيار dependent لتحقيق ذلك. توجّه إلى نموذج Article (app/models/article.rb) وعدّله بالصورة التالية: class Article < ApplicationRecord has_many :comments, dependent: :destroy validates :title, presence: true, length: { minimum: 5 } end الاستيثاق Authentication في Rails إن كنت ترغب في نشر المدوّنة على الإنترنت، سيكون بإمكان أي شخص إضافة وتعديل وحذف المقالات والتعليقات فيها. يقدّم Rails نظام استيثاق HTTP بسيط يمكن استخدامه في التطبيقات البسيطة كتطبيقنا هذا. سنحتاج في المتحكّم ArticlesController إلى وسيلة لمنع وصول الشخص غير المستوثق منه إلى الأحداث التي يتضمّنها هذا المتحكّم، ويمكن استخدام تابع http_basic_authenticate_with لتحقيق ذلك. ولاستخدام نظام الاستثياق سنقوم بالإفصاح عنه في بداية ملف المتحكّم ArticlesController in app/controllers/articles_controller.rb وسنستوثق من جميع الأحداث المتوفّرة في هذا المتحكّم عدا حدثي index وshow: class ArticlesController < ApplicationController http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show] def index @articles = Article.all end # بقيّة الشيفرة ... كذلك سنسمح للمستخدمين المستوثق منهم فقط بحذف التعليقات، لذا أضف الشيفرة التالية إلى المتحكّم CommentsController في الملف app/controllers/comments_controller.rb: class CommentsController < ApplicationController http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy def create @article = Article.find(params[:article_id]) # ... end # بقيّة الشيفرة ... والآن إن حاولت إنشاء مقالة جديدة، ستتلقّى طلب استيثاق كهذا: جدير بالذكر أنّ هناك العديد من وسائل الاستيثاق في تطبيقات Rails، أشهرها Devise rails engine و Authlogic. إطار العمل Rails ونظام الترميز UTF-8 إن أسهل طريقة للعمل مع Rails هي تخزين جميع البيانات الخارجية بنظام الترميز UTF-8، وإن لم تفعل ذلك فغالبًا ما تقوم مكتبات Ruby وإطار العمل Rails بتحويل البيانات الأصلية إلى هذا الترميز، ولكن لا يمكن الاعتماد على هذه المكتبات بصورة تامّة، ويفضّل التأكد من أنّ جميع البيانات الخارجية مرمّزة بهذا النظام. وفي حال حدوث أي خطأ في نظام الترميز فإن الحروف ستظهر في المتصفّح غالبًا على هيئة أشكال معينية سوداء بداخلها علامة استفهام، أو قد تظهر الحروف على هيئة رموز غريبة كأن يظهر الرمز “ü” بدلاً من الحرف “ü”. يتّخذ Rails بعض الإجراءات في نظامه الداخلي للتقليل من المسبّبات الشائعة لهذه المشاكل والتي يمكن الكشف عنها وتصحيحها بصورة تلقائية. ولكن، إن كنت تتعامل مع بيانات من مصادر خارجية غير مخزّنة بترميز UTF-8، لن يكون Rails قادرًا على الكشف بصورة تلقائية عن أسباب المشكلة أو تقديم حلّ لها. وهناك مصدران شائعان للبيانات غير المخزّنة بترميز UTF-8: محرر النصوص: تحفظ معظم محرّرات النصوص الملفات البرمجية بصيغة UTF-8، وإن لم يقم محرّر النصوص الذي تستخدمه في كتابة الشيفرات البرمجية بذلك، فقد ينتج عن ذلك تحوّل الحروف الخاصّة أو حروف اللغات الأخرى غير الإنكليزية إلى التحول في المتصفّح إلى أشكال معينية بداخلها علامة استفهام. ينطبق هذا الأمر كذلك على ملفات الترجمة i18n. تجدر الإشارة إلى أنّه تتيح معظم محررات النصوص التي لا تحفظ الملفات البرمجية بهذا الترميز افتراضيًّا (مثل Dreamweaver) إمكانية تغيير الترميز الافتراضي للملفات المحفوظة إلى نظام UTF-8، وننصح بالقيام بذلك. قاعدة البيانات: يحوّل Rails البيانات القادمة من قاعدة البيانات إلى ترميز UTF-8، ولكن إن لم يكن هذا نظام الترميز هذا مستخدمًا من طرف قاعدة البيانات فلن يكون بالإمكان تخزين جميع المحارف المدخلة من قبل المستخدم. فعلى سبيل المثال، إن كان نظام الترميز الداخلي لقاعدة البيانات هو Latin-1 وأدخل المستخدم كلمات باللغة الروسية أو العربية أو اليابانية، فستخسر البيانات إلى الأبد بمجرد دخولها إلى قاعدة البيانات. لذا ينصح دائمًا بتحويل نظام الترميز الداخلي في قاعدة البيانات إلى نظام UTF-8. المصدر: توثيقات Ruby on Rails.
  22. تحدّثنا في الجزء السابق من هذه السلسلة عن النماذج في إطار العمل Ruby on Rails وتعرّفنا على طريقة إنشائها والتعامل معها من خلال كتابة الشيفرة المسؤولة عن حفظ المقالة الجديدة في قاعدة البيانات. في الجزء الثاني من هذا الموضوع سنتعلّم كيفية ربط نموذجين مع بعضهما البعض من خلال إنشاء نموذج جديد خاصّ بالتعليقات. ولكن قبل ذلك سنكمل ما بدأناه في الدروس السابقة من السلسلة في بناء عمليات “CRUD” حيث غطّينا سابقًا عمليتي الإنشاء Create و القراءة Read، وسنغطي اليوم العمليتين المتبقّيتين وهما التحديث Update والحذف Destroy. تحديث المقالات الخطوة الأولى في عملية تحديث المقالات هي إضافة حدث edit إلى المتحكم ArticlesController بين حدثي new و create وكما يلي: def new @article = Article.new end def edit @article = Article.find(params[:id]) end def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end سيتضمن العرض استمارة مشابهة لتلك التي استخدمناها في إنشاء المقالات الجديدة. أنشئ ملفًّا باسم app/views/articles/edit.html.erb وأضف إليه الشيفرة التالية: <h1>Edit article</h1> <%= form_for(@article) do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2> <%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved: </h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %> سنوجّه الاستمارة هذه المرة إلى حدث update والذي لم نقم بتعريفه حتى الآن. يؤدي تمرير كائن المقالة للتابع إلى إنشاء عنوان url لإرسال استمارة المقالة التي تم تعديلها، ومن خلال هذا الخيار نخبر Rails بأنّنا نرغب في أن يتم إرسال هذا النموذج من خلال فعل HTTP PATCH وهو أحد أفعال HTTP التي تستخدم في تحديث الموارد حسب بروتوكول REST. يمكن أن يكون المعامل الأول لـ form_for كائنًا، مثلًا @articl، والذي سيؤدي بالدالة المساعدة إلى ملء الاستمارة بالحقول التابعة للكائن، ويؤدي تمرير الرمز (:article) بنفس اسم المتغيّر من نوع instance (@article) إلى نفس النتيجة تلقائيًا. والآن سنقوم بإنشاء الحدث update في المتحكّم app/controllers/articles_controller.rb وسنضيفه بين حدث create والتابع ذي المحدّد الخاصّ private: def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end def update @article = Article.find(params[:id]) if @article.update(article_params) redirect_to @article else render 'edit' end end private def article_params params.require(:article).permit(:title, :text) end يستخدم الحدث update عندما ترغب في تحديث سجل موجود في قاعدة البيانات، ويستقبل هذا الحدث جدول تقطيع hash يحتوي الخصائص التي ترغب في تحديثها. وكما سبق، في حال وجود خطأ في عملية التحديث سنعرض الاستمارة على المستخدم من جديد. سنستخدم التابع article_params الذي عرّفناه في وقت سابق للحدث create. لا حاجة لتمرير جميع الخصائص لغرض تحديثها، فعلى سبيل المثال، إن تم استدعاء @article.update(title: 'A new title') فسيقوم Rails بتحديث خاصية العنوان فقط، ويترك باقي الخصائص دون تعديل. أخيرًا، نرغب في عرض رابط إلى الحدث edit في الصفحة التي نعرض فيها قائمة المقالات، لذا توجّه إلى الملف app/views/articles/index.html.erb وأضف الرابط ليظهر إلى جانب رابط “Show”: <table> <tr> <th>Title</th> <th>Text</th> <th colspan="2"></th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> <td><%= link_to 'Show', article_path(article) %></td> <td><%= link_to 'Edit', edit_article_path(article) %></td> </tr> <% end %> </table> سنضيف كذلك رابطًا إلى قالب app/views/articles/show.html.erb ليظهر رابط “Edit” في صفحة المقالة أيضًا: ... <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> هذا هو شكل تطبيقنا حتى هذه اللحظة: استخدام الملفات الجزئية partials لإزالة التكرار من العروض تبدو صفحة تحرير المقالة مشابهة تمامًا لصفحة إنشاء مقالة جديدة، وفي الواقع تستخدم الصفحتان الشيفرة ذاتها لعرض الاستمارة. سنقوم الآن بالتخلص من هذا التكرار باستخدام ملفات العرض الجزئية. تحمل هذه الملفات أسماء تبدأ بالمحرف (_). أنشئ ملفًّا جديدًا باسم _form.html.erb ضمن المسار app/views/articles/ وأضف إليه الشيفرة التالية: <%= form_for @article do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2> <%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved: </h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> لاحظ أننا لم نغيّر شيئًا باستثناء الإعلان عن التابع form_for وسبب استخدام هذه الأسلوب المختصر والبسيط في الإعلان عن التابع form_for للتعبير عن الاستمارتين هو أن @article عبارة عن مورد يرتبط بمجموعةٍ من مسارات RESTful، وبإمكان Rails أن يخمّن عنوان URI والتابع الذي يجب استخدامه. والآن لنقم بتحديث العرض app/views/articles/new.html.erb لاستخدام الملف الجزئي الذي أنشأناه وسنقوم بإعادة كتابة العرض من جديد وكما يلي: <h1>New article</h1> <%= render 'form' %> <%= link_to 'Back', articles_path %> ثم قم بالأمر عينه في ملف العرض app/views/articles/edit.html.erb: <h1>Edit article</h1> <%= render 'form' %> <%= link_to 'Back', articles_path %> حذف المقالات هذه هي العملية الأخيرة ضمن عمليات CRUD، وبحسب معايير REST فإن المسار الذي يؤدي إلى حذف المقالات وكما يظهر في مخرجات الأمر bin/rails routes هو: DELETE /articles/:id(.:format) articles#destroy يجب استخدام الفعل DELETE في المسار المسؤول عن حذف الموارد، أما في حال استخدام الفعل GET فسيكون بالإمكان إنشاء رابط خبيث كهذا الرابط مثلًا: <a href='http://example.com/articles/1/destroy'>look at this cat!</a> سنستخدم التابع delete لحذف المصادر، وهذا المسار مرتبط بالحدث destroy ضمن المتحكّم app/controllers/articles_controller.rb والذي لم نقم بإنشائه بعد. عادة ما يكون التابع destroy التابع الأخير ضمن المتحكّم، وكما هو الحال مع بقية التوابع العامّة public يجب الإعلان عنه قبل أي توابع خاصّة أو محميّة protected. def destroy @article = Article.find(params[:id]) @article.destroy redirect_to articles_path end الصورة النهائية للمتحكّم ArticleController في الملف app/controllers/articles_controller.rb هي: class ArticlesController < ApplicationController def index @articles = Article.all end def show @article = Article.find(params[:id]) end def new @article = Article.new end def edit @article = Article.find(params[:id]) end def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end def update @article = Article.find(params[:id]) if @article.update(article_params) redirect_to @article else render 'edit' end end def destroy @article = Article.find(params[:id]) @article.destroy redirect_to articles_path end private def article_params params.require(:article).permit(:title, :text) end end يمكن استدعاء التابع destroy في كائنات التسجيلة النشطة Active Record عندما ترغب في حذفها من قاعدة البيانات. لاحظ أنّنا لسنا بحاجة لإضافة عرض خاص بهذا الحدث لأنّنا نعيد توجيه المستخدم إلى الحدث index. أخيرًا أضف رابط ‘Destroy’ إلى القالب app/views/articles/index.html.erb لنربط كل الصفحات مع بعضها البعض. <h1>Listing Articles</h1> <%= link_to 'New article', new_article_path %> <table> <tr> <th>Title</th> <th>Text</th> <th colspan="3"></th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> <td><%= link_to 'Show', article_path(article) %></td> <td><%= link_to 'Edit', edit_article_path(article) %></td> <td><%= link_to 'Destroy', article_path(article), method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </table> استخدمنا هنا التابع link_to بطريقة مختلفة، حيث مررّنا اسم المسار كمعامل ثانٍ، ثمّ مرّرنا الخيارات الأخرى بعد ذلك. تستخدم الخيارات method: :delete وdata: { confirm: 'Are you sure?' } كخصائص HTML5 بحيث يؤدي الضغط على الرابط إلى عرض مربع حوار للتأكد من رغبة المستخدم في حذف المقالة، ثم إرسال الرابط باستخدام التابع delete. تتمّ تعملية التحقّق هذه بواسطة ملف JavaScript الذي يحمل الاسم rails-ujs والموجود بصورة افتراضية في مخطط التطبيق (app/views/layouts/application.html.erb)، وفي حال عدم وجود هذا الملف لن يظهر مربع الحوار التأكيدي للمستخدم. تهانينا أصبح بإمكانك الآن إنشاء وعرض وسرد وتحديث وحذف المقالات في مدوّنتك. إضافة النموذج الخاصّ بالتعليقات سنقوم الآن بإنشاء نموذج جديد في تطبيقنا هذا ستكون وظيفته التعامل مع التعليقات. إنشاء النموذج لإنشاء النموذج الخاص بالتعليقات سنتبع الأسلوب السابق نفسه وذلك باستخدام أداة المولّد لإنشاء نموذج يحمل الاسم Comment ويمثّل مرجعًا إلى المقالة. اكتب الأمر التالي في سطر الأوامر: $ bin/rails generate model Comment commenter:string body:text article:references سينشئ هذا الأمر أربعة ملفات: الملف Purpose الملف/المجلد الوظيفة db/migrate/20140120201010_create_comments.rb ملف التهجير المسؤول عن إنشاء جدول التعليقات في قاعدة البيانات (سيحمل اسم الملف لديك ختمًا زمنيًا مختلفًا) app/models/comment.rb النموذج الخاص بالتعليقات test/models/comment_test.rb ملف الاختبارات الخاص بنموذج التعليقات test/fixtures/comments.yml نماذج تعليقات تستخدم في إجراء الاختبارات لنلق نظرة في البداية على ملف app/models/comment.rb: class Comment < ApplicationRecord belongs_to :article end كما تلاحظ فمحتوى هذا الملف مشابه لنموذج Article الذي أنشأناه سابقًا، والفارق الوحيد هو السطر belongs_to :article والذي ينشئ رابطًا بين النموذجين، وسنتحدّث عن الروابط بعد قليل. أما الكلمة المفتاحية (:references) ضمن الأمر الذي قمنا بتنفيذه في سطر الأوامر، فهي نوع خاص من البيانات بالنسبة للنماذج. تنشئ هذه الكلمة المفتاحية عمودًا في الجدول الموجود في قاعدة البيانات يحمل اسم النموذج الذي تمّ تمريره إلى هذه الكلمة مع إضافة _id والذي يمثّل عددًا صحيحًا. ستتضح الأمور أكثر بالنسبة إليك إن تفحّصت ملف db/schema.rb أدناه. قام Rails - بالإضافة إلى إنشاء النموذج - بإنشاء تهجير وظيفته إنشاء الجدول المقابل للنموذج في قاعدة البيانات: class CreateComments < ActiveRecord::Migration[5.0] def change create_table :comments do |t| t.string :commenter t.text :body t.references :article, foreign_key: true t.timestamps end end end يُنشئ السطر t.references عمودًا من نوع integer باسم article_id إضافة إلى فهرس index خاص بهذا العمود وقيد مفتاح خارجي Foreign Key Constraint والذي يشير إلى عمود id في جدول المقالات. والآن نفذ التهجير باستخدام الأمر التالي: $ bin/rails db:migrate ينفّذ Rails التهجيرات غير المنفّذة فقط؛ لذا ستكون نتيجة الأمر التالي كما يلي: == CreateComments: migrating ================================================= -- create_table(:comments) -> 0.0115s == CreateComments: migrated (0.0119s) ======================================== ربط النماذج مع بعضها البعض تسهّل روابط التسجيلة النشطة تكوين العلاقات بين النماذج، وفي حالتنا هذه سنُنشئ علاقة بين جدولي التعليقات والمقالات، ولو فكّرنا في طبيعة العلاقة التي تربط بينهما فسنجد أنه: ينتمي كل تعليق إلى مقالة واحدة. تمتلك المقالة الواحدة العديد من التعليقات. يستخدم Rails صياغة مشابهة للربط بين النماذج، وقد شاهدنا في نموذج Comment في الملف app/models/comment.rb الشيفرة المسؤولة عن ربط كل تعليق بمقالة واحدة: class Comment < ApplicationRecord belongs_to :article end سنحتاج الآن إلى تكوين الجانب الثاني من الرابطة، أي ربط المقالات بالتعليقات، لذا توجّه إلى الملف app/models/article.rb وعدّله بالصورة التالية: class Article < ApplicationRecord has_many :comments validates :title, presence: true, length: { minimum: 5 } end والآن أصبح النموذجان مرتبطين مع بعضهما البعض تلقائيًا، فعلى سبيل المثال، في حال كان لدينا متغيّر @article والذي يمثّل مقالة معيّنة، يمكن استدعاء جميع التعليقات المرتبطة بتلك المقالة على هيئة مصفوفة وذلك من خلال @article.comments. إضافة مسار خاص بالتعليقات كما هو الحال مع متحكم welcome سنحتاج إلى إضافة مسار نحدّد من خلاله العنوان الذي نرغب في استخدامه لمشاهدة التعليقات؛ لذا افتح ملف config/routes.rb مرة أخرى، وعدّله كما يلي: resources :articles do resources :comments end بهذه الطريقة تصبح التعليقات بمثابة موارد مضمّنة في المقالات، وهذه الطريقة هي جزء من العلاقة الهرمية التي تنشأ بين المقالات والتعليقات. إنشاء المتحكّم الخاصّ بالتعليقات بعد أن انتهينا من إعداد النموذج، أصبح بإمكاننا الآن إنشاء المتحكّم الخاص بالتعليقات، وسنستخدم أداة المولّد كما فعلنا سابقًا: $ bin/rails generate controller Comments سينشئ هذا الأمر خمسة ملفات إضافة إلى مجلّد فارغ: الملف/المجلد الوظيفة app/controllers/comments_controller.rb المتحكّم الخاص بالتعليقات /app/views/comments يتم تخزين العروض الخاصّة بالتعليقات في هذا المجلد test/controllers/comments_controller_test.rb ملف الاختبار الخاصّ بالمتحكّم app/helpers/comments الملف الخاصّ بمساعد العرض app/assets/javascripts/comments.coffee ملف CoffeScript الخاصّ بالمتحكّم app/assets/stylesheets/comments.scss أوراق الأنماط المتتالية CSS الخاصّة بالمتحكّم كما هو الحال مع أي مدوّنة، فإن القرّاء سيكتبون تعليقاتهم بعد قراءة المقالة مباشرة، وبعد أن يرسلوا تعليقاتهم يتم توجيههم إلى صفحة عرض المقالة ليتمكّنوا من مشاهدة التعليقات. وستكون وظيفة المتحكّم CommentsController هي توفير التوابع اللازمة لإنشاء التعليقات وحذف التعليقات المزعجة حال وصولها. سنقوم أولًا بتعديل قالب عرض المقالات app/views/articles/show.html.erb لنتمكن من إضافة تعليق جديد: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> ستضيف الشيفرة السابقة استمارة إلى صفحة عرض المقالات يمكن من خلالها إضافة تعليق جديد من خلال استدعاء الحدث create ضمن المتحكّم CommentsController. ويستخدم الاستدعاء form_for مصفوفة ستعمل على إنشاء مسار متداخل nested route مثل: /articles/1/comments. لنجرِ الآن التعديلات اللازمة على الحدث create في الملفّ app/controllers/comments_controller.rb: class CommentsController < ApplicationController def create @article = Article.find(params[:article_id]) @comment = @article.comments.create(comment_params) redirect_to article_path(@article) end private def comment_params params.require(:comment).permit(:commenter, :body) end end ستتعقّد الأمور هنا قليلًا وذلك بسبب التداخل nesting الحاصل بين المسارات، إذ في كل مرة يتمّ فيها طلب تعليق معيّن يجب أن يتابع ذلك الطلب المقالة التي يرتبط بها هذا التعليق، وبالتالي استدعاء التابع find في نموذج Article والمسؤول عن اختيار المقالة المطلوبة حسب المعرّف المحدّد في المسار. بالإضافة إلى ذلك، استفدنا من بعض التوابع التي تقدّمها عملية الربط بين النموذجين، فقد استخدمنا التابع create على @article.comments لإنشاء التعليق وحفظه، وسيؤدي هذا إلى ربط التعليق الجديد بالمقالة المحدّدة. وبعد إنشاء التعليق الجديد نعيد توجيه المستخدم إلى المقالة الأصلية باستخدام الدالة المساعد article_path(@article). وكما شاهدنا تستدعي هذه الدالة الحدث show ضمن المتحكّم ArticlesController والذي يعمل بدوره على تصيير القالب show.html.erb، وهو المكان الذي نرغب أن تظهر التعليقات فيه؛ لذا سنقوم بإجراء التعديلات اللازمة على الملف app/views/articles/show.html.erb. <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <% @article.comments.each do |comment| %> <p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> <% end %> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> أصبح بإمكانك الآن إضافة المقالات والتعليقات إلى مدوّنتك وعرضها في الأماكن الصحيحة. في الدرس القادم سنكمل العمل على التعليقات، حيث سنستخدم الملفات الجزئية لترتيب القوالب أوّلًا، ثم نضيف إمكانية حذف التعليقات من قاعدة البيانات، وفي الختام سنتطرّق إلى عملية الاستيثاق Authentication بصورة سريعة ومبسّطة. المصدر: توثيقات Ruby on Rails.
  23. تعرّفنا في الدرس السابق بإيجاز على طريقة عمل إطار العمل Ruby on Rails حيث تعرّفنا على المتحكّمات والعروض وبدأنا بإنشاء تطبيق المدوّنة البسيطة وأنشأنا في الدرس السابق الاستمارة الخاصة بإضافة مقالة جديدة، ولكن وصلنا إلى النقطة التي نحتاج فيها إلى تخزين المقالة في قاعدة البيانات، وهنا يأتي دور النماذج Models. تحمل النماذج في Rails اسمًا بصيغة المفرد في حين يحمل الجدول المرتبط بها في قاعدة البيانات اسمًا بصيغة الجمع. تتيح أداة المولّد generator في Rails إنشاء النماذج ويلجأ أغلب المطوّرين إلى هذه الأداة لإنشاء النماذج. لإنشاء نموذج جديد استخدم الأمر التالي في سطر الأوامر: $ bin/rails generate model Article title:string text:text من خلال هذه الأمر نخبر Rails بأننا نرغب في إنشاء نموذج باسم Article إلى جانب خاصّية title من نوع string، وخاصّية text من نوع text. تضاف هذه الخواص بصورة تلقائية إلى جدول المقالات في قاعدة البيانات ويتم ربطها بنموذج Article. ويستجيب Rails لهذا الأمر بإنشاء عدد من الملفات، وما يهمّنا منها الآن هما app/models/article.rb و db/migrate/20140120191729_create_articles.rb (لاحظ أن اسم الملف الثاني يختلف قليلًا عن هذا الاسم). الملف الثاني مسؤول عن إنشاء بنية قاعدة البيانات، وهو ما سنتحدث عنه بعد قليل. إجراء عملية التهجير Migration كما لاحظنا فإن الأمر bin/rails generate model قد أنشأ ملف تهجير لقاعدة البيانات داخل المجلد db/migrate. والتهجيرات هي عبارة عن أصناف مصمّمة لتسهيل عملية إنشاء الجداول في قواعد البيانات والتعديل عليها. يستخدم Rails أوامر rake لإجراء التهجيرات، ويمكن التراجع عن عملية التجهير بعد إجرائها على قاعدة البيانات. تتضمّن أسماء ملفات التهجير ختمًا زمنيًا لضمان معالجة هذه الملفات حسب التسلسل الزمني لإنشائها. لو ألقينا نظرة في ملف db/migrate/YYYYMMDDHHMMSS_create_articles.rb (تذكّر أن الملف عندك يحمل ختمًا زمنيًّا مختلفًا) فسنجد التالي: class CreateArticles < ActiveRecord::Migration[5.0] def change create_table :articles do |t| t.string :title t.text :text t.timestamps end end end ستنشئ عملية التهجير أعلاه تابعًا يحمل اسم `change` والذي يتم استدعاؤه عند إجراء عملية التهجير. حتى الحدث المُعرّف ضمن التابع قابل للتراجع، ما يعني أن Rails قادر على التراجع عن التغييرات الحاصلة من إجراء عملية التهجير في حال أردت ذلك في وقت لاحق. عند إجراء عملية التهجير هذه سيتم إنشاء جدول باسم `articles` يتضمن عمودًا من نوع `string` وآخر من نوع `text`، إضافة إلى عمودين للختم الزمني يمكن لـ Rails من خلالهما متابعة تواريخ إنشاء وتعديل المقالات. لتنفيذ عمية التهجير توجّه إلى سطر الأوامر ونفذ الأمر التالي: $ bin/rails db:migrate سينفّذ Rails أمر التهجير التالي وسيخبرك بإنشاء جدول Articles. == CreateArticles: migrating ================================================== -- create_table(:articles) -> 0.0019s == CreateArticles: migrated (0.0020s) ========================================= حفظ البيانات بواسطة المتحكّم سنعود الآن إلى المتحكّم ArticlesController، حيث سنعمل على تعديل الحدث create ليستخدم النموذج الجديد Article لحفظ البيانات في قاعدة البيانات. افتح الملف app/controllers/articles_controller.rb وعدّله بالصورة التالية: def create @article = Article.new(params[:article]) @article.save redirect_to @article end يمكن استحداث initialize كل نموذج في Rails مع الخصائص Attributes المرتبطة به، والتي يتم ربطها تلقائيًا مع الأعمدة المقابلة في قاعدة البيانات. وقد قمنا بذلك في السطر الأول في الحدث create (هل تذكر params[:article] والذي يضمّ الخصائص التي نريدها). بعد ذلك يمكن حفظ النموذج في قاعدة البيانات من خلال الدالة @article.save. وفي النهاية نعيد توجيه المستخدم إلى الحدث show الذي سنعرّفه في وقت لاحق. توجّه الآن إلى العنوان http://localhost:3000/articles/new وستتلقّى الخطأ التالي: يدعم Rails العديد من مزايا الأمان التي تساعد في كتابة تطبيقات أمينة، ونحن الآن نتعامل مع إحدى هذه المزايا. تدعى هذه الميزة بالمعاملات القوية strong parameters والتي تجبرنا على تحديد المعاملات المسموح بها في الأحداث الموجودة ضمن المتحكم. ما الفائدة من ذلك؟ صحيح أن القدرة على إضافة جميع المعاملات إلى النموذج دفعة واحدة وبصورة تلقائية يختصر الكثير من الجهد بالنسبة للمبرمج، إلا أنّ البرنامج يكون في هذه الحالة عرضة للاستخدامات الخبيثة. فماذا لو تمّ إنشاء طلب إلى الخادوم يتضمن استمارة إنشاء مقالة جديدة إضافة إلى حقول أخرى تحتوي على معلومات تضرّ بالتطبيق؟ سيتم إسناد المعلومات الإضافية بصورة شاملة “Mass Assignment” إلى النموذج ثم إلى قاعدة البيانات جنبًا إلى جنب مع البيانات الأصلية، وهذا قد يتسبب في تعطيل عمل برنامجك أو قد يحدث ما هو أسوأ من ذلك بكثير. يجب علينا إذًا تحديد المعاملات المسموح بإدخالها إلى النموذج، وفي حالتنا هذه سنسمح بإدراج معاملي title و text ونطلب توفّر قيم لهما. وللقيام بذلك عدّل السطر الأول من حدث create بالصورة التالية: @article = Article.new(params.require(:article).permit(:title, :text)) غالبًا ما يتمّ تحديد المعاملات المسموح بإدخالها إلى النموذج في تابع خاص ليصبح بالإمكان إعادة استخدامها بواسطة عدة أحداث في المتحكّم نفسه مثل حدثي create و update، إضافة إلى ذلك يكون هذا التابع خاصًّا وذلك باستخدام المحدّد private لضمان عدم إمكانية استدعائه من خارج السياق المقرّر له، وبالشكل التالي: def create @article = Article.new(article_params) @article.save redirect_to @article end private def article_params params.require(:article).permit(:title, :text) end عرض المقالات إن قمت بتعبئة استمارة المقالة الجديدة وإرسالها فستتلقّى خطأ مفاده عدم عثور Rails على الحدث show، لذا سنقوم بإنشاء هذا الحدث الآن. كما رأينا سابقًا في مخرجات الأمر bin/rails routes فإن مسار الحدث show هو: article GET /articles/:id(.:format) articles#show تعني الصيغة الخاصة :id أن هذا المسار يطلب وجود معامل :id والذي يمثّل في حالتنا هذه معرّف المقالة. وكما فعلنا سابقًا، يجب علينا إضافة الحدث show إلى ملف المتحكّم app/controllers/articles_controller.rb وتحديد العرض المرتبط به. عادة ما تأخذ أحداث CRUD في المتحكّمات الترتيب التالي: index, show, new, edit, create, update, destroy. ويمكن اتّباع الترتيب الذي يعجبك، ولكن تذكّر أن هذه التوابع هي توابع عامّة public، ويجب الإعلان عنها قبل الإعلان عن التوابع الخاصّة. سنضيف الآن الحدث show آخذين ما سبق بعين الاعتبار: class ArticlesController < ApplicationController def show @article = Article.find(params[:id]) end def new end # بقيّة الشيفرة ..... استخدمنا الدالة Article.find للبحث عن المقالة المطلوبة، وذلك بتمرير المعامل params[:id] للحصول على قيمة المعرّف من الطلب الذي أرسلته صفحة إنشاء مقالة جديدة. كذلك استخدمنا متغيّرًا من نوع instance (مسبوقًا بعلامة @) ليكون مرجعًا لكائن المقالة، وذلك لأنّ Rails يمرّر هذا النوع من المتغيّرات إلى العرض. أنشئ الآن ملفًّا جديدًا باسم show.html.erb في المسار app/views/articles/ وأضف إليه الشيفرة التالية: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> ستكون الآن قادرًا على إنشاء مقالة جديدة؛ لذا توجّه إلى العنوان http://localhost:3000/articles/new وجرّب إضافة مقالة جديدة. عرض قائمة بمقالات المدوّنة نحتاج الآن إلى عرض قائمة بجميع المقالات الموجودة في المدونة، وسيكون المسار المرتبط بهذا الحدث وبحسب مخرجات الأمر bin/rails routes كالتالي: articles GET /articles(.:format) articles#index أضف الحدث index المرتبط بهذا المسار إلى المتحكّم ArticlesController في الملف app/controllers/articles_controller.rb. من الممارسات الشائعة بين المطوّرين هو كتابة الحدث index في بداية المتحكّم: class ArticlesController < ApplicationController def index @articles = Article.all end def show @article = Article.find(params[:id]) end def new end # بقية الشيفرة ... بعدها أضف العرض الخاصّ بهذا الحدث والموجود في المسار app/views/articles/index.html.erb والذي يتضمّن الشيفرة التالية: <h1>Listing articles</h1> <table> <tr> <th>Title</th> <th>Text</th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> <td><%= link_to 'Show', article_path(article) %></td> </tr> <% end %> </table> توجّه الآن إلى العنوان http://localhost:3000/articles في المتصفّح وستشاهد قائمة بجميع المقالات التي أنشأتها مسبقًا. إضافة الروابط للتنقل بين صفحات المدوّنة أصبح بمقدورنا الآن إنشاء وعرض وسرد قائمة المقالات المتوفّرة في المدونة، ولكنّنا بحاجة إلى بعض الروابط التي تساعدنا في التنقل بين صفحات الموقع. افتح الملف app/views/welcome/index.html.erb وعدّله كما يلي: <h1>Hello, Rails!</h1> <%= link_to 'My Blog', controller: 'articles' %> التابع link_to هو أحد دوال العروض المساعدة والمضمّنة في Rails، ووظيفة هذا التابع إنشاء رابط تشعّبي بالاستناد إلى النصّ الذي نمرّره إليه، وهو في حالتنا هذه المسار الخاص بسرد قائمة المقالات. لنضف بعض الروابط إلى العروض الأخرى، ولنبدأ بإضافة رابط إنشاء مقالة جديدة إلى الملف app/views/articles/index.html.erb قبل وسم <table>: <%= link_to 'New article', new_article_path %> سيوجّه هذا الرابط المستخدم إلى الصفحة التي تتضمن استمارة إنشاء مقالة جديدة. سنضيف رابطًا آخر إلى الملفّ app/views/articles/new.html.erb بعد الاستمارة مباشرة، ليتمكن المستخدم من العودة إلى الصفحة الرئيسية: <%= form_for :article, url: articles_path do |f| %> ... <% end %> <%= link_to 'Back', articles_path %> وأخيرًا، سنضيف رابطًا إلى القالب app/views/articles/show.html.erb يوجّه المستخدم إلى الصفحة الرئيسية أيضًا، وبهذا يصبح بميسور من يستعرض مقالة معيّنة أن يرجع إلى الصفحة التي تعرض جميع المقالات: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <%= link_to 'Back', articles_path %> التحقّق من المدخلات لو نظرت إلى النموذج الذي أنشأناه سابقًا فسترى أنّ الملف بسيطٌ للغاية: class Article < ApplicationRecord end لاحظ أنّ الصنف Article موروث من الصنف ApplicationRecord وهو بدوره موروث من الصنف ActiveRecord::Base والذي يتضمّن الكثير من الوظائف والإجراءات الخاصة بالنماذج، مثل عمليات CRUD البسيطة (Create, Read, Update, Destroy) والتحقّق من البيانات Validation، إضافة إلى عمليات البحث المعقّدة وربط النماذج المختلفة مع بعضها البعض. ويقدّم إطار العمل Rails توابع متعدّدة تساعد في التحقق من البيانات المرسلة إلى النموذج. افتح الملف app/models/article.rb وأضف إليه الشيفرة التالية: class Article < ApplicationRecord validates :title, presence: true, length: { minimum: 5 } end سيضمن هذا التغيير امتلاك كل مقالة جديدة في المدونة لعنوان يتألف من خمسة أحرف على الأقل. يتيح Rails التحقّق من أمور متنوّعة في النماذج، مثل التحقّق من وجود أو عدم تكرار الأعمدة والتحقّق من تنسيقها ووجود كائنات مرتبطة بها. لنجرّب الآن استدعاء الدالة @article.save في مقالة لا تمتلك عنوانًا وسنلاحظ أن الدالة ترجع القيمة false. لو عدنا إلى المتحكّم في الملف app/controllers/articles_controller.rb مرّة أخرى سنلاحظ بأنّنا لم نتحقّق من النتيجة التي ترجعها الدالة @article.save ضمن الحدث create. إن فشلت الدالة @article.save في أداء عملها، يجب أن نعيد المستخدم إلى استمارة إضافة مقالة جديدة، وللقيام بذلك عدّل حدثي new و create في الملف app/controllers/articles_controller.rb بالصورة التالية: def new @article = Article.new end def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end private def article_params params.require(:article).permit(:title, :text) end سينشئ الحدث new متغيّرًا جديدًا من نوع instance يحمل الاسم @article وستتعرّف إلى سبب القيام بذلك بعد قليل. لاحظ أنّنا استخدمنا render داخل الحدث create بدلًا من redirect_to في حال إرجاع الدالة save للقيمة false. يستخدم التابع render لكي يتم تمرير الكائن @article إلى القالب الجديد عند تصييره. وعملية التصيير هذه تتم ضمن نفس الطلب الناتج من إرسال الاستمارة، في حين أن الدالة redirect_to تتسبّب في إرسال طلب آخر. الآن أعد تحميل الصفحة ذات العنوان http://localhost:3000/articles/new وحاول إضافة مقالة جديد دون عنوان، سترى بأنّ Rails يعيدك إلى صفحة الاستمارة، ولكن هذا ليس مفيدًا جدًّا. يجب إخبار المستخدم بحدوث خطأ ما، وللقيام بذلك عدّل الملف app/views/articles/new.html.erb للتحقّق من رسائل الخطأ: <%= form_for :article, url: articles_path do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2> <%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved: </h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %> تحقّقنا في البداية من وجود أي أخطاء من خلال @article.errors.any?، وفي حال وجودها نعرض قائمة الأخطاء المتوفّرة من خلال @article.errors.full_messages. تأخذ الدالة pluralize معاملين الأول رقمي والثاني نصّي. إن كان العدد أكبر من واحد تتحوّل السلسلة النصّية تلقائيًا إلى صيغة الجمع. إن سبب إضافة @article = Article.new إلى المتحكّم ArticlesController هو أنّنا لو لم نقم بذلك لأصبحت قيمة المتغيّر @articl هي nil، وسيؤدي الاستدعاء @article.errores.any? إلى إطلاق خطأ. يحيط Rails الحقول التي تحتوي على أخطاء بوسم <div> مع صنف CSS يحمل الاسم field_with_errors، ويمكنك تعريف صنف CSS هذا لتنسيق الحقول حسب الرغبة. والآن ستتلقّى رسالة خطا مرتّبة عندما تحاول حفظ مقالة لا تتضمن عنوانًا. في الدرس القادم سنواصل العمل على النموذج حيث سنكتب الشيفرة المسؤولة عن تعديل المقالات وحذفها، ثم سنتعرّف على طريقة إنشاء علاقات بين النماذج المختلفة من خلال إضافة نموذج للتعامل مع التعليقات في المدونة. المصدر: توثيقات Ruby on Rails.
  24. تعرّفنا في الدرس السابق على طريقة تثبيت إطار العمل Rails وبدأنا العمل على مشروعنا الأول وهو عبارة عن مدوّنة بسيطة، وقمنا بتشغيل الخادوم الخاص بإطار العمل. وفي هذا الدرس سنتعرّف على آلية عمل إطار العمل Rails من خلال مثال بسيط، ثم نشرع بعده ببناء مدونتنا البسيطة لنتعرف بصورة أكبر على العديد من المفاهيم التي يستند إليها هذا الإطار. آلية عمل إطار Rails سنتعرّف على آلية عمل إطار Ruby on Rails من خلال مثال بسيط نعرض فيه مجموعة من الكلمات في الصفحة الرئيسية لتطبيقنا، وللقيام بذلك سنحتاج إلى متحكّم Controller وعرض View. وظيفة المتحكّم هي استقبال الطلبات الواردة إلى التطبيق، وتربط المسارات Routes بين الطلبات والمتحكّمات. وغالبًا ما يكون هناك أكثر من مسار واحد لكل متحكّم، ويمكن للمسارات المختلفة أن تؤدّي إلى أحداث Actions مختلفة، ووظيفة الحدث هي جمع المعلومات اللازمة وتقديمها إلى العرض. أمّا وظيفة العرض فواضحة من اسمه، وهي عرض المعلومات التي حصل عليها من الحدث بصورة مقروءة للإنسان. من الضروري هنا الانتباه إلى أن عملية جمع المعلومات تتمّ ضمن المتحكّم وليس ضمن العرض، ومهمّة العرض الوحيدة هي عرض المعلومات. يستخدم إطار Rails لغة قوالب خاصّة في العروض تدعى eRuby (اختصار لـ Embedded Ruby) والتي تُعالج بواسطة دورة الطلب في Rails قبل أن تُرسل إلى المستخدم. سلنجأ إلى أداة المولّد generator لإنشاء متحكّم يحمل اسم Welcome يتضمّن حدثًا باسم index. اكتب الأمر التالي في سطر الأوامر: $ bin/rails generate controller Welcome index سيقوم Rails بإنشاء مسار وعدد من الملفات. create app/controllers/welcome_controller.rb route get 'welcome/index' invoke erb create app/views/welcome create app/views/welcome/index.html.erb invoke test_unit create test/controllers/welcome_controller_test.rb invoke helper create app/helpers/welcome_helper.rb invoke test_unit invoke assets invoke coffee create app/assets/javascripts/welcome.coffee invoke scss create app/assets/stylesheets/welcome.scss ما يهمّنا من هذه الملفات هما المتحكم والموجود في المسار app/controllers/welcome_controller.rb والعرض الموجود في المسار app/views/welcome/index.html.erb. افتح الملف app/views/welcome/index.html.erb في محرّر النصوص المفضّل لديك، واحذف محتوياته واستبدلها بالشيفرة التالية: <h1>Hello, Rails!</h1> بعد أن أنشئنا المتحكم والعرض يجب علينا إخبار Rails بالمسار الذي سيأخذ المستخدم إلى هذا العرض. نحن نرغب في حالتنا هذه أن يتم توجيه المستخدم إلى العرض عندما يتوجّه إلى العنوان http://localhost:3000، ولكن صفحة الترحيب تشغل هذا المسار في الوقت الحاضر. بعد ذلك يجب إخبار Rails بموقع الصفحة الرئيسية ليتمكّن من عرضها للمستخدم. افتح الملف config/routes.rb في محرّر النصوص: Rails.application.routes.draw do get 'welcome/index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end الشيفرة أعلاه موجودة في ملف المسارات والذي يتضمّن مدخلات DSL خاصّة (DSL اختصار لـ domain-specific language) والتي تخبر Rail بطريقة ربط الطلبات الواردة إلى التطبيق بالمتحكمات والأحداث. عدّل هذا الملف بالصورة التالية: Rails.application.routes.draw do get 'welcome/index' root 'welcome#index' end من خلال السطر root 'welcome#index' يربط إطار العمل Rails الطلبات الواردة إلى المسار الرئيسي في التطبيق مع الحدث index في المتحكّم Welcome، أما السطر get 'welcome/index' فيربط من خلاله Rails الطلبات الواردة إلى العنوان http://localhost:3000/welcome/index بنفس الحدث ونفس المتحكّم، وقد تمّ إنشاء هذه الشيفرة من قبل أداة المولّد. والآن شغّل الخادوم الخاص بـ Rails ثمّ توجّه في المتصفّح إلى العنوان http://localhost:3000، وستشاهد عبارة “Hello, Rails!” الموجودة في ملف app/views/welcome/index.html.erb وهذا يعني أن هذا المسار قد توجّه فعلًا إلى الحدث index في المتحكم Welcome والذي قام بدوره بتصيير العرض بصورة صحيحة. البدء بإنشاء المدوّنة بعد أن تعرّفنا على المتحكّمات والأحداث والعروض، لنبدأ العمل على مدوّنتنا. سننشئ الآن ما يسمى في إطار العمل Rail بالمورد resourse، والمورد هو مصطلح يعبّر عن مجموعة من العناصر المتشابهة، مثل المقالات، الأشخاص أو الحيوانات. ويمكن إنشاء create وقراءة read وتحديث update وإلغاء destroy العناصر في المورد، وتسمى هذه العمليات بعمليات CRUD. يقدّم Rails تابعًا باسم resources يمكن استخدامه للإفصاح عن مورد بنمط REST القياسي. يجب إضافة مورد المقالة إلى ملف config/routes.rb وكما يلي: Rails.application.routes.draw do get 'welcome/index' resources :articles root 'welcome#index' end والآن إن قمت بتنفيذ الأمر bin/rails routes فستشاهد جميع المسارات الخاصّة بجميع الأحداث التي تتّصف بنمط REST. سنتعرّف على معنى عمود prefix وبقية الأعمدة في وقت لاحق، ولكن لاحظ أنّ Rails قد خمّن صيغة المفرد (article) واستخدمها في السياق الصحيح. $ bin/rails routes Prefix Verb URI Pattern Controller#Action articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create new_article GET /articles/new(.:format) articles#new edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update DELETE /articles/:id(.:format) articles#destroy root GET / welcome#index سنعمل الآن على إضافة خاصيتي إنشاء المقالات وعرضها، وستكون الاستمارة Form المسؤولة عن ذلك بالشكل التالي: قد تبدو الاستمارة بدائيًّة ولكنّها كافية في الوقت الحاضر، وسنعمل على تحسين مظهرها فيما بعد. إنشاء المتحكّمات والمسارات اللازمة في البداية يجب اختيار المسار الذي سيوجّه المستخدم إلى استمارة إنشاء المقالة الجديدة، وسنستخدم المسار /articles/new للقيام بهذه المهمّة، بعدها يصبح بميسور التطبيق أن يتلقّى الطلبات على هذا المسار. توجّه الآن في متصفحك إلى الرابط http://localhost:3000/articles/new وستتلقّى الخطأ التالي: يحدث هذا الخطأ لأنّ المسار بحاجة إلى متحكّم يرسل إليه الطلب؛ لذا سنقوم بإنشاء متحكّم باسم ArticlesController، وذلك من خلال تنفيذ الأمر التالي: $ bin/rails generate controller Articles افتح الملف الذي قمت بإنشائه app/controllers/articles_controller.rb وسترى متحكّمًا فارغًا: class ArticlesController < ApplicationController end المتحكّم عبارة عن صنف Class موروث من ApplicationController وسنقوم بتعريف التوابع ضمن هذا الصنف والتي ستمثل الأحداث الخاصّة بهذا المتحكم، وهذه الأحداث هي المسؤولة عن تنفيذ عمليات CRUD على المقالات الموجودة في تطبيقنا. إن أعدت تحميل الصفحة ستتلقّى خطأً جديدًا: يشير هذا الخطأ إلى عدم قدرة Rails على إيجاد الحدث new ضمن المتحكّم ArticlesController الذي قمنا بإنشائه للتوّ. وهذا عائد إلى أنّ المتحكّمات تكون فارغة عند إنشائها إلا إذا حدّدنا الأحداث المطلوبة خلال عملية إنشاء المتحكّم. ولتعريف حدث جديد بصورة يدوية، سنحتاج فقط إلى تعريف تابع جديد ضمن المتحكم. افتح الملف app/controllers/articles_controller.rb وضمن الصنف ArticlesController عرّف تابعًا جديدًا وكما يلي: class ArticlesController < ApplicationController def new end end والآن أعد تحميل الصفحة في المتصفّح وستتلقّى خطأً آخر: يظهر هذا الخطأ لأنّ Rails يتوقّع أنه يجب أن تمتلك الأحداث الصرفة المشابهة لهذا الحدث عروضًا ترتبط معها لعرض المعلومات التي تتضمنها، ونظرًا لعدم وجود أي عرض مرتبط بهذا الحدث، أطلق Rails هذا الخطأ. لنطّلع على رسالة الخطأ الكاملة: لنستعرض النص السابق سريعًا، ونفهم مضمونه بصورة جيدة. يحدّد الجزء الأول من نصّ الخطأ القالب المفقود، وفي هذه الحالة القالب المفقود هو articles/new. يبدأ Rails بالبحث عن هذا القالب، وإن لم يفلح في العثور عليه فإنه يحاول تحميل قالب يدعى application/new وذلك لأنّ المتحكّم ArticleController هو صنف موروث من المتحكّم ApplicationController. يتضمن الجزء الثاني من رسالة الخطأ request.formats والذي يحدّد صيغة القالب الذي سيتم عرضه كاستجابة للطلب الذي تلقّاه التطبيق، وقد تم اختيار صيغة text/html لأنّنا طلبنا هذه الصفحة بواسطة المتصفح؛ لذا يبحث Rails عن قوالب HTML. أما request.variant فيحدد طبيعة الأدوات المادّية physical devices التي سيتم تقديمها مع الطلب وتساعد Rails في تحديد القالب الذي سيستخدمه في الاستجابة، وهو فارغ نظرًا لعدم توفّر المعلومات. أبسط قالب يمكن أن يعمل في هذه الحالة هو القالب الموجود في المسار app/views/articles/new.html.erb. هذه اللاحقة مهمّة للغاية: فالجزء الأول من اللاحقة (.html) يعبّر عن صيغة القالب، أمّا الجزء الثاني (.erb) فيمثّل المعالج handler الذي سيتم استخدامه في تصيير القالب. يحاول Rails البحث عن قالب يحمل الاسم articles/new ضمن المجلد app/views. يجب أن تكون صيغة هذا القالب هي HTML حصرًا، وسيكون erb المعالج الافتراضي لـ HTML. يستخدم Rails عددًا من المعالجات مثل: builder والمستخدم في إنشاء قوالب XML، وcoffee الذي يستخدم لغة CoffeeScript لبناء قوالب JavaScript. بما أنّنا نرغب في بناء استمارة HTML جديدة فسنستخدم لغة ERB والتي تتيح لنا تضمين لغة Ruby في HTML. إذًا سيكون اسم القالب articles/new.html.erb وسيكون ضمن المجلد app/views الخاص بالتطبيق. أنشئ ملفًّا جديدًا باسم new.html.erb في المسار app/views/articles وأضف إليه ما يلي: <h1>New Article</h1> أعد تحميل الصفحة وستلاحظ ظهور العنوان في رأس الصفحة، وهذا يعني أن هناك تناغمًا تامًّا بين كلّ من المسار والمتحكم والحدث والعرض. الاستمارة الأولى سنستخدم منشئ النماذج form builder لإنشاء الاستمارة الأولى في هذا القالب. يمكن استخدام منشئ النماذج الرئيسي في Rails باستخدام التابع المساعد form_for. أضف الشيفرة التالية في الملف app/views/articles/new.html.erb: <%= form_for :article do |f| %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> أعد تحميل الصفحة وستلاحظ ظهور نفس الاستمارة التي عرضناها في المثال السابق. كما تلاحظ فإنّ بناء الاستمارات في Rails أمر سهلٌ للغاية. عندما نستدعي التابع form_for فإننا نمرّر إليه عنصرًا يحدّد الهدف من هذه الاستمارة، والهدف في حالتنا هذه هو :article. يُستخدم الكائن FormBuilder والذي مثّلناه بـ f لبناء عنصري label وحقلي نصوص text fields لكلّ من عنوان المقال ومتنها. وفي النهاية استدعينا التابع submit لإنشاء زرّ اﻹرسال الخاصّ بالاستمارة. ولكن تعاني هذه الاستمارة من مشكلة صغيرة. لو تفحّصت شيفرة HTML التي تم توليدها من خلال الشيفرة السابقة فستلاحظ أن خاصية action التابعة للاستمارة تشير إلى المسار articles/new وهذا المسار هو نفسه الذي يقودنا إلى هذه الصفحة، والمفروض أن يستخدم هذا المسار لعرض استمارة إنشاء مقالة جديدة لا غير. إذًا يجب أن تستخدم الاستمارة مسارًا آخر، ويمكن القيام بذلك بسهولة من خلال استخدام الخيار :url في form_for. عادة ما يحمل الحدث المسؤول عن إرسال مقال جديد اسم “create”، لذا يجب توجيه الاستمارة إلى هذا الحدث. عدّل السطر الذي يتضمن form_for في ملف app/views/articles/new.html.erb كما يلي: <%= form_for :article, url: articles_path do |f| %> في هذا المثال تم تمرير الدالة المساعدة articles_path إلى الخيار :url، ولنتعرّف على نتيجة هذا التعديل سنلقي نظرة على مخرجات الأمر bin/rails routes في سطر اﻷوامر: $ bin/rails routes Prefix Verb URI Pattern Controller#Action articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create new_article GET /articles/new(.:format) articles#new edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update DELETE /articles/:id(.:format) articles#destroy root GET / welcome#index توجّه الدالة المساعدة articles_pat الاستمارة إلى نمط URI المرتبط لاحقة articles وسيرسل الاستمارة - تلقائيًا - طلبًا من نوع POST إلى المسار، والذي يرتبط بالحدث create التابع للمتحكّم ArticlesController. بعد أن أنشأنا الاستمارة وعرّفنا المسار المرتبط به، أصبح باﻹمكان تعبئة حقول الاستمارة والضغط على زرّ اﻹرسال لبدء عملية إنشاء مقال جديد، ولكن عند إرسال المقال ستتلقّى الخطأ المتوقَّع التالي: علاج هذا الخطأ بسيط وهو إنشاء الحدث create ضمن المتحكّم ArticlesController. إنشاء المقالات سنقوم الآن بتعريف الحدث create ضمن صنف ArticlesController في الملف app/controllers/articles_controller.rb بعد الحدث new وكما يلي: class ArticlesController < ApplicationController def new end def create end end إن أعدت إرسال الاستمارة مرة أخرى فستلاحظ عدم حدوث أي تغيير في الصفحة. لا تقلق، هذا الأمر عائد إلى أنّ Rails يعيد الاستجابة “204 No Content” لأي حدث لا يحدّد الاستجابة المطلوبة. وقد أضفنا الحدث create دون تحديد الاستجابة المطلوبة منه، وهي في حالتنا هذه، إنشاء مقالة جديدة في قاعدة البيانات. عند إرسال الاستمارة يتم إرسال الحقول الخاصة بها إلى Rails على هيئة معاملات parameters، يمكن الإشارة إليها في الأحداث التابعة للمتحكّم وذلك لإنجاز مهّمة ما، ولتعرف كيف تبدو هذه المعاملات عدّل حدث create بالصورة التالية: def create render plain: params[:article].inspect end يأخذ التابع render هنا جدول تقطيع Hash بسيط مع المفتاح :plain والقيمة هي تابع params [:article].inspect. توابع params هي الكائن الذي يمثّل المعامل (أو الحقل) المأخوذ من الاستمارة. ويعيد تابع params كائن من نوع ActionController::Parameters والذي يتيح لنا الوصول إلى مفاتيح جدول التقطيع من خلال السلاسل النصّيّة Strings أو الرموز Symbols. وفي حالتنا هذه، فإن المعاملات المهمّة هي المعاملات المأخوذة من الاستمارة. لتوضيح عمل توابع params، إليك المثال التالي: في عنوان URL هذا: http://www.example.com/?username=dhh&email=dhh@mail.com فإن params[:username] تحمل القيمة “dhh” و params[:email] تحمل القيمة “dhh@mail.com”. والآن أعد إرسال الاستمارة مرة أخرى وستشاهد شيئًا مماثلًا لما يلي: <ActionController::Parameters {"title"=>"First Article!", "text"=>"This is my first article."} permitted: false> يعرض هذا الحدث المعاملات الخاصة بالمقالة والمأخوذة من الاستمارة، ولكن ليس هذا ما نريده بالضبط، فنحن نشاهد المعاملات ولكنّها لا تقدّم أي فائدة تذكر في حالتها هذه. في الدرس القادم سنتعرّف على النماذج Models في إطار العمل Rails وسنستخدمها في إضافة مقالة جديدة إلى قاعدة البيانات التابعة للتطبيق. المصدر: توثيقات Ruby on Rails.
  25. Rails هو إطار عمل لتطوير تطبيقات الويب مكتوب بلغة Ruby البرمجية، وقد صُمّم إطار العمل هذا لتسهيل برمجة تطبيقات الويب من خلال وضع بعض الافتراضات المسبقة حول ما يحتاجه المطوّر للشروع في العمل. يتيح إطار العمل هذا كتابة شيفرات أقل وإنجاز أمور أكثر من أي لغة برمجية أو أطر عمل أخرى. يفترض Rails أن هناك طريقة مثلى لإنجاز الأعمال، وقد صمّم لتشجيع المطوّر على اتباع هذه الطرق وفي بعض الأحيان حثّه على ترك البدائل الأخرى، وقد تلاحظ زيادة هائلة في إنتاجيتك إن تعلّمت الأسلوب الذي يتبعه إطار العمل هذا، وقد يؤدي الالتزام بالعادات القديمة المتّبعة في لغات البرمجة الأخرى إلى تجربة غير جيّدة في تطوير التطبيقات باستخدام Rails. تستند فلسفة Rails إلى ركيزتين أساسيتين: لا تكرّر نفسك (Don’t Repeat Yourself): ينصّ هذا المفهوم على وجوب تمثيل أي جزء من أجزاء المعرفة بصورة مفردة وغير مبهمة وموثوقة في النظام. اتّباع هذا المفهوم في كتابة النصوص البرمجية وعدم تكرار المعلومات ذاتها باستمرار يؤدي إلى زيادة قابلية صيانة الشيفرة المكتوبة وامتلاكها القدرة على التوسّع إضافة إلى انخفاض نسبة الأخطاء فيها. مبدأ “Convention Over Configuration”: يمتلك Rails مبادئ خاصّة ترتبط بتحديد الطريقة المثلى في إنجاز الأعمال في تطبيق الويب، ويعتمد على هذه المبادئ بصورة افتراضية بدلًا من إجبار المطوّر على تحديد تفاصيل صغيرة في عمله من خلال عدد كبير من اﻹعدادات. ما الذي تحتاجه للبدء هذه السلسلة مخصصة للمبتدئين الذين يرغبون في الشروع ببناء التطبيقات على إطار العمل Rails، ولا يفترض وجود أي خبرة سابقة في هذا المجال، ولكن هناك بعض الأمور التي يجب تثبيتها قبل الشروع في التعلم: تثبيت الإصدار 2.2.2 من لغة Ruby البرمجية أو أي إصدار أعلى. تثبيت النسخة الملائمة من حزمة التطوير Development Kit إن كنت من مستخدمي نظام التشغيل ويندوز. نظام إدارة الحزم (الجواهر) RubyGems والذي يأتي مع لغة Ruby بصورة افتراضية. تثبيت قواعد بيانات SQLite3. ذكرنا أنّ إطار العمل Rails مبني باستخدام لغة Ruby البرمجية، وإن كنت لا تمتلك خبرة مسبقة بهذه اللغة يمكنك مراجعة الدروس المتوفّرة حول أساسيات لغة Ruby في الأكاديمية إضافة إلى الموقع الرسمي للغة. إنشاء مشروع جديد في Rails الهدف من هذه السلسلة هو بناء مدوّنة بسيطة باستخدام إطار العمل Rails، وقبل البدء في بناء التطبيق يجب التأكد من تثبيت Rails في جهازك. سنستخدم الرمز $ للتعبير عن سطر الأوامر في الأنظمة الشبيهة بـ UNIX. أما في نظام ويندوز فسترى سطر الأوامر يبدأ بشيء مشابه لهذه الصيغة: <C:\source_code. تثبيت Rails توجّه إلى سطر الأوامر في جهازك (في نظام macOS افتح الطرفية Terminal.app، وفي نظام ويندوز اختر “Run” من قائمة ابدأ ثم اكتب cmd.exe). في البداية سنتأكد من إصدار لغة Ruby المثبت في الجهاز: $ ruby -v ruby 2.3.1p112 بالنسبة لقواعد البيانات SQLite3 فعادة ما تكون مثبّتة بشكل افتراضي في الأنظمة الشبيهة بـ UNIX. أما في نظام ويندوز، فإن قمت بتثبيت Rails من خلال مثبت Rails فإن SQLite ستكون مثبتة على جهازك أيضاً. يمكنك كذلك مراجعة موقع SQLite3 للاطلاع على تعليمات تثبيت قاعدة البيانات. يمكن التحقق من سلامة تثبيت SQLite3 من خلال الأمر التالي: $ sqlite3 --version إن كانت SQLite مثبتة في الجهاز فسيظهر رقم الإصدار المثبت في سطر الأوامر. لتثبيت Rails استخدم أمر التثبيت gem install الذي يتيحه RubyGems وبالصورة التالية: $ gem install rails وللتأكد من أن عملية التثبيت قد تمّت بصورة صحيحة، يجب أن تكون قادرًا على تنفيذ الأمر التالي في سطر الأوامر: $ rails --version يجب أن تحصل على نتيجة مشابهة لهذه: Rails 5.1.0. إنشاء تطبيق المدوّنة يقدّم إطار العمل Rails مجموعة من الشيفرات تحمل اسم المولّدات generators، وتهدف هذه الشيفرات إلى تسهيل عمل المطوّر من خلال إنشاء الملفات المطلوبة للشروع في مهمّة معيّنة. مولّد التطبيق الجديد هو أحد هذه المولّدات ويعمل على إنشاء تطبيق Rails جديد وتوفير عناء كتابته من قبل المطور. ولاستخدام المولّد توجّه في سطر الأوامر إلى المجلد الذي ترغب في إنشاء التطبيق فيه واكتب الأمر التالي: $ rails new blog سينشئ هذا الأمر تطبيقًا جديدًا باسم Blog في مجلد blog وسيثبت اعتماديات gem الموجودة في GEMfile باستخدام الأمر bundle install. يمكنك الاطلاع على جميع الخيارات المتاحة في سطر الأوامر والتي يتقبّلها مولّد تطبيقات Rails وذلك من خلال تنفيذ الأمر: rails new -h بعد إنشاء تطبيق المدوّنة، توجّه في سطر الأوامر إلى المجلّد الخاص به: $ cd blog ستلاحظ أنّ مجلّد المدونة يتضمن بعض الملفات والمجلّدات التي تم إنشاؤها بصورة تلقائية والتي تمثّل العمود الفقري لتطبيق Rails. سينحصر الجزء الأكبر من عملنا ضمن مجلد app، ولكن لا بأس في الاطلاع بصورة سريعة على وظيفة هذه الملفات والمجلّدات: الملف أو المجلد الوظيفة /app يتضمن هذا المجلّد: المتحكّمات controllers، النماذج models، العروض views، الدوال المساعدة helpers، دوال البريد اﻹلكتروني mailers، القنوات channels، الوظائف jobs، والأصول assets الخاصّة بالتطبيق. سيتركّز عملنا ضمن هذا المجلد. /bin يتضمّن هذا المجلد شيفرات Rails المسؤولة عن تشغيل التطبيق ويمكن أن يتضمن شيفرات أخرى تستخدم في تثبيت وتحديث ونشر وتشغيل التطبيق. /config يتضمن الإعدادات الخاصة بمسارات التطبيق routes، وقاعدة البيانات وغير ذلك config.ru ملف إعدادات Rack يستخدم في خواديم Rack لتشغيل التطبيق عليها. /db يتضمّن مخطط قاعدة البيانات الحالية، إضافة إلى تهجيرات قاعدة البيانات. Gemfile, Gemfile.lock يتيح هذان الملفان تحديد اعتماديات gem المطلوبة لتطبيق Rails. يستخدم Bundler هذه الملفات. لمزيد من المعلومات توجّه إلى موقع Bundler الإلكتروني. /lib الوحدات الموسّعة الخاصة بالتطبيق. /log ملفات log الخاصة بالتطبيق. /public المجلد الوحيد الذي سيظهر على حاله بعد نشر التطبيق، ويتضمن الملفات الساكنة و ملفات الأصول المجمّعة. Rakefile يحدّد هذا الملف ويحمّل المهامّ التي يمكن تنفيذها بواسطة سطر الأوامر. يتم تعريف المهامّ ضمن مكوّنات Rails. ولإضافة مهامّ جديدة يجب عدم تعديل هذا الملف، بل إضافة ملفات إلى مجلّد lig/tasks. README.md الملفّ التعريفي الخاصّ بالتطبيق، ويمكن من خلاله تقديم نبذة تعريفية عن التطبيق والمهام التي يؤديها وطريقة التثبيت وغير ذلك من المعلومات. /test يضمّ هذا المجلد جميع الأمور المرتبطة بالاختبارات. /tmp يضمّ هذا المجلّد الملفّات المؤقتة (مثل ملفات الذاكرة المخبئية وملفات pid). /vendor ستجد هنا جميع شيفرات الطرف الثالث، وعادة ما يتضمن جواهر مطوّرة من قبل أشخاص أو شركات. gitignore. يخبر هذا الملف نظام التحكم في النسخ Git عن الملفات أو (الأنماط) التي ينبغي عليه تجاهلها. لتعرف المزيد راجع سلسلة دروس Git في الأكاديمية. مرحبًا Rails لنحاول في البداية إظهار بعض النصوص على الشاشة وبصورة سريعة، وللقيام بذلك، ستحتاج إلى تشغيل الخادوم الخاص بـ Rails. تشغيل خادوم Rails يتضمّن إطار العمل Rails خادوم ويب خاصًّا به وكل ما نحتاج إليه هو تشغيله وذلك من خلال تنفيذ الأمر التالي في سطر الأوامر ضمن مجلد blog: $ bin/rails server إن كنت تستخدم نظام ويندوز يجب تمرير الشيفرات في مجلد bin إلى مفسّر Ruby مباشرة: ruby bin\rails server تنفيذ هذا الأمر سيؤدي إلى تشغيل Puma، وهو خادوم ويب مضمّن بصورة افتراضية في إطار العمل Rails. حان الآن وقت الولوج إلى تطبيقنا من خلال المتصفح وذلك بالتوجه إلى الرابط http://localhost:3000/. ستظهر الصفحة التالية لتشير إلى نجاحنا في إنشاء أول مشروع على Ruby on Rails. المصدر: توثيقات Ruby on Rails.
×
×
  • أضف...