محمد طاهر الموسوي

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

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

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

  • Days Won

    21

السُّمعة بالموقع

111 Excellent

المعلومات الشخصية

  • النبذة الشخصية كيميائي ومصمم ومترجم عراقيّ، أهوى الخطّ العربي، وأعشق كذلك البرمجة وأحاول دائمًا تطوير مهاراتي فيها.

10 متابعين

آخر الزُوّار

3,362 زيارة للملف الشّخصي
  1. اكتشفت مؤخرًا المتعة الكبيرة في استخدام مكتبة [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.
  2. من المؤكّد أنّك ترغب في زيادة وعي الجمهور بمشروعك التجاري، وتدفعك هذه الرغبة إلى زيادة التركيز على أدوات التسويق. وهناك اعتقاد سائد بأنّ برمجيات ومنصّات التسويق تلائم الشركات الكبيرة حصرًا، ولكن الواقع عكس ذلك تمامًا. وبصرف النظر عن طبيعة مشروعك التجاري أو سنوات الخبرة التي تتمتع بها، فإن خير وسيلة لمواكبة السوق الذي يمتاز بالتغير الدائم هي الاستفادة من أدوات التسويق المختلفة ضمن خطتك التسويقية، لتضمن بهذه الطريقة انتشار علامتك التجارية بين شريحة أكبر من الناس، وجذب العملاء والشركاء، وغير ذلك الكثير. ولمساعدتك في هذه المهمّة سنقدّم في هذا المقال نبذةً مختصرةً حول سبع أدوات فعّالة يمكنك الاستفادة منها لتحقيق أهدافك. بعض الإحصائيات المرتبطة بأتمتة التسويق يقرّ 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
  3. Lumen هو إطار عمل مصغّر Micro-framework مبني باستخدام إطار العمل Laravel، وهما من صنع Taylor Otwell. صُمّم Lumen لتطوير الخدمات المصغّرة مثل التطبيقات الصغيرة أو خدمات الويب، والهدف من تطويره هو الحصول على أقصى قدر من السرعة، فقد تم استبدال مكوّن التوجيه Symfony في Laravel بـ FastRoute في Lument لتحسين الأداء وزيادة السرعة. في هذا الدرس سننشئ واجهة برمجية بنمط RESTful، وستعمل هذه الواجهة البرمجية على تخزين وعرض المعلومات الخاصّة بالكتب. تثبيت Lumen سنستخدم Composer لتثبيت lumen، لذا سنتحقّق من وجود هذه المكتبة في النظام، وذلك بكتابة الأمر التالي في الطرفية أو في سطر الأوامر: composer إن ظهرت أوامر 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.
  4. قد تحتاج في بعض الأحيان إلى تشغيل شيفرة معيّنة دون انتظار المستخدم للقيام بذلك، يمكنك - والحال هذه - أن تنفّذ الشيفرة في الخلفية وأن تخفيها عن المستخدم، وبهذا تزيد من سرعة وفعّالية موقعك الإلكتروني. تعتمد هذه الطريقة على ما يسمى بشيفرات الصدفة 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.
  5. تقدّمت منذ فترة بطلب إلى مطوّري إطار عمل 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.
  6. سواء أكنت في طور بناء موقع إلكتروني لأحد العملاء وترغب في إطلاق حملة تسويقية، أو كنت ترغب فقط في زيادة نسب المشاهدة والوصول إلى موقعك الإلكتروني، فإنّ التهيئة لمحركات البحث هي من الأمور المهمّة لتحقيق ذلك، وربّما تكون العامل الأساسي في نجاح أو فشل المدوّنات أو المشاريع التجارية على شبكة الإنترنت. وعلى الرغم من أنّ محركات البحث الحديثة قد وصلت إلى مستويات كبيرة من التطوّر، وعلى الرغم من أنّ خوارزميات البحث تتطوّر بصورة يومية، إلّا أنّ محرّكات البحث هذه غير قادرة على استيعاب وفهم صفحات الويب بنفس الأسلوب الذي يتّبعه الإنسان. سنتعرّف في هذا المقال على كيفية تهيئة محرّكات البحث في تحديد الهدف من كل صفحة من صفحات الموقع باتباع بعض الخطوات البسيطة، وسنتعرّف كذلك على فائدة عملية التحسين هذه بالنسبة للمستخدمين. لو أخذنا بنظر الاعتبار أن 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
  7. أعترف بأنّي لا أمتلك خبرة كبيرة في مكتبة 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.
  8. 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.
  9. تقدّم المواصفات الجديدة في 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.
  10. ما هو شعورك عندما تقضي أسابيع أو شهور أو ربّما سنوات في بناء وتطوير منتجك الرائع ثم لا يشتري أحد منك هذا المنتج؟ غالبًا ما يعود سبب إخفاق المنتج اﻷول إلى خطأ واحد وبسيط. عنوان المقال يبدو كعنوان مضلّل يهدف إلى جذب القراء لا أكثر، ولكنّ مضمونه صحيح أيضًا، وبما أنّك قد شعرت برغبة ملحّة في النقر على العنوان، فيمكنني التخمين بأنّك تتحلّى بهاتين الصفتين: أنت شخص مبتكر تحبّ صناعة اﻷشياء. تحب صنع اﻷشياء وبيعها كذلك. ويمكنني أن أضيف إلى الصفة اﻷولى أنّك تمتلك الكثير من الأفكار التي يمكنك من خلالها إنجاز اﻷمور على أتمّ وجه، وأنّك من النوع الذي يمتلك همّة عالية ويشمّر عن ساعديه ويبدأ بكتابة الشيفرات والتصميم والكتابة والتسجيل وغير ذلك من اﻷعمال. تؤدي هذه الرغبة الكبيرة في إنجاز الأعمال - والمعروفة بالانحياز للعمل 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
  11. بما أنّ 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.
  12. أنت تتعرض للتقييم في كلّ مرة تقابل فيها شخصًا ما سواء أأدركت ذلك أم لا، ولا أقصد هنا تقييم أعمالك وتصاميمك وبرامجك التي تطوّرها، مع أن هذا النوع من التقييم مهمّ بكل تأكيد. ما أعنيه هو تقييم شخصيتك ومواقفك وأسلوبك في الكلام وهندامك ومظهرك الخارجي، فهذه الأمور هي أوّل ما يراه الأشخاص الذين تقابلهم وتكوّن علاقات معهم، وهذا الأمر مفصليّ بالنسبة للمستقلّ الذي يسعى إلى توسيع قاعدة عملائه. في هذا المقال سنتطرق إلى بعض الطرق التي تساعد في تحسين سمعتك كمستقلّ، الأمر الذي سيؤدّي إلى تعزيز سيرتك المهنيّة بصورة كبيرة. كل الأشخاص نقّاد نحن ننتقد كلّ ما يصادفنا وكلّ من نلتقي به وبصورة يومية، وعندما تلتقي بعميلك المحتمل فإنّك ستقرّر - دون أن تشعر - ما إذا كنت ستوافق على العمل معه أم لا. يقال أنّ الانطباع الأوّلي يدوم إلى الأبد؛ وانطلاقًا من هذه المقولة عليك أن تسعى جاهدًا لرسم صورة مشرّفة عندما تقدّم نفسك أو عملك لعميل محتمل. ويمكن القول أنّ أسلوب التواصل مع الآخرين هو أحد أهم الوسائل التي تساعد في عرض جوانبك الجيّدة للعملاء المحتملين. أذكر أنّي تعاملت مع مصمّمة لمجرد أنّي سمعت - وعن طريق الصدفة - أسلوبها في التخاطب مع الآخرين. لقد كانت مهذّبة وصادقة ومفعمة بالثقة، وكانت تتمتّع بمهارات تواصل مذهلة انعكست بصورة جليّة على مظهرها وأسلوبها في الكلام. وكان انطباعي الأوّل عنها: “تعرف هذه المرأة ما تقوم به جيّدًا، وإن عملت معها فسأكون مطمئنًّا إلى أنّها ستنجز العمل على أتمّ وجه”. يجب عليك كمستقلّ أن تبذل قصارى جهدك لتمنح الآخرين مثل هذا الانطباع، فلربّما ينظر إليك عميلك الكبير القادم دون أن تشعر بذلك. مكوّنات السمعة الجيدة هناك ثلاثة أمور أساسية يجب تحقيقها لبناء سمعة مهنية جيّدة: أن تكون محبوبًا. أن تكون محلًّا للثقة. أن تكون محترمًا. تستند السمعة المهنيّة الممتازة على هذه الركائز الثلاثة، ولا غنى لك عن أي واحدة منها، فحبّ الناس لك يعني أنّك أهلٌ للثقة، فما من أحد يثق بمن لا يحبّ، وبمجرّد أن تنال ثقة الناس فإنّك ستكون قادرًا على كسب احترامهم. يجب عليك كمصمّم أن تتحلّى بسلوك يبعث على الثقة والإعجاب لتكون قادرًا على تجاوز منافسيك والوصول إلى نوعية العملاء الذين ترغب حقًّا في التعامل معهم. قد يكون هذا الأمر صعبًا في البداية، خصوصًا إن كنت من الذين يشعرون براحة أكبر عند الجلوس أمام الحاسوب ولا يحبّذون الاختلاط مع الناس، ولكن الخطوة الأولى تتلخّص في تغيير الصورة التي يراك الناس بها. قد لا تحصل على نتيجة مثالية في بداية الأمر، ولكن مع الملاحظة والتمرين المستمرّين، ستكون قادرًا على نيل محبّة الناس وثقتهم بك في وقت قصير جدًّا. اسأل واستمع قد تتسائل: “هذا رائع جدًّا، ولكن كيف يكون بميسوري تغيير صورتي أمام الآخرين؟”. لا أدّعي أن هذا الأمر سيكون سهلًا، ولكن يمكنك اتباع بعض الخطط والأساليب التي ستساعدك على تحسين صورتك وسمعتك أمام الناس. اطلب من معارفك أن يقدّموا رأيهم فيك عندما يقابلونك وبكلّ صراحة، واستمع إلى ما يقولون بانتباه شديد وصدر رحب. هل يشعر المقرّبون منك أنّك شخص لحوح؟ هل يرون أنّك تقاطع الآخرين كثيرًا أثناء المحادثة؟ أتبدو في نظرهم شخصًا متكبّرًا للغاية أم خجولًا جدًّا أم غريب الأطوار؟ يرتكب جميع البشر الأخطاء، ولكن الاستماع إلى النقد الصادق وتحمّله هو الوسيلة الوحيدة لتجاوز هذه الأخطاء، وبطبيعة الحال، لن تكون قادرًا على تجاوز المشكلة ما لم تعي وجودها. من الطرق النافعة كذلك فيما يتعلّق بهيأتك ومهارات التواصل الاجتماعي، هي التدرّب على هذه الأمور أمام الكاميرا وليس المرآة، إذ من الضروري أن تسجّل حديثك وطريقتك في الإجابة على الأسئلة… الخ لتتمكّن من تشخيص نقاط الضعف ومن ثمّ معالجتها. يمكن لبضع ساعات من التدريب أن تحسّن مهارات التواصل لديك بصورة كبيرة جدًّا، وقد تتسبّب مراجعة التسجيلات في بعض الإحراج، لكنّ أداءك سيتحسّن بسرعة كبيرة. لا تغفل عن هدفك الأساسي يتطلب بناء السمعة الحسنة الكثير من الوقت والجهد، لذا احرص على أن تعالج أخطاءك قبل أن تتسبّب في مشاكل دائمية لا يمكن حلّها، فهناك حدّ معين يصبح من المستحيل بعده إرجاع الأمور إلى نصابها. والمشاهير هم خير دليل على ذلك، والفرص المتاحة أمام هؤلاء الأشخاص تفوق الفرص المتاحة أمام بقية الناس، ولكن من المؤكّد أنّك سمعت بأن أحد المشاهير قد ارتكب فعلًا مشينًا أطاح بسمعته إلى درجة يستحيل أن تعود بعدها إلى سابق عهدها. لا يدرك هؤلاء الأشخاص - في معظم الأحيان - أنّ لأفعالهم أثرًا بالغًا في سمعتهم وبنظرة الناس إليهم، وأنّ السيرة المهنيّة للمشاهير تحت رحمة الرأي العام، ومن اليسير أن تصبح الثروة والشهرة سببًا في ارتكاب أخطاء تودي بالمرء إلى الهاوية. الحفاظ على السمعة الحسنة إن الحفاظ على السمعة الحسنة يتطلّب منك الانتباه واليقظة الدائمين، وأهمّ وسيلة لإحراز التقدّم والحصول على العملاء وتوسيع علاقاتك الاجتماعية هي أن تكون محبوبًا لدى الناس، وبميسورك أن تكون مستعدًّا لمواجهة أيّة مشكلة قد تؤثّر سلبًا على سمعتك وذلك بالتفكير الدائم في الصورة التي ترغب في عكسها للناس. استمرّ في وضع الأهداف لنفسك واسع لتحقيقها على الدوام، وطوّر شخصيتك وأسلوبك، وابحث دائمًا عن النقد البنّاء وضع لنفسك خطّة منظّمة لتغيير سلوكك لتبني الصورة التي ترغب أن يراك الناس فيها. ترجمة - وبتصرّف - للمقال The Importance of Your Reputation as a Freelance Creative لصاحبته Addison Duvall. حقوق الصورة البارزة محفوظة لـ Freepik
  13. ﻻ بد أن تمرّ الشركة الناشئة - مهما كانت طبيعة فريق العمل - بمرحلة الوقوع في مشاكل لا تستطيع الخروج منها. والتحدّي الحقيقي - والحال هذه - هو تحديد الوقت اللازم لحلّ المشاكل التي تواجه الشركة، فهل ينبغي متابعة المشكلة والعمل على حلّها بشكل كامل مهما استغرق ذلك من وقت، أم يجدر طلب المساعدة عند العجز عن إيجاد الحلّ المناسب؟ تساعد قاعدة الـ 15 دقيقة كل فرد من أعضاء فريقك على إدراك القيمة الحقيقية لمفهوم الاكتفاء الذاتي، وتلزمهم في الوقت عينه بأن يلجأوا إلى أطواق النجاة عندما تقتضي الحاجة ذلك. تعلّمت هذه القاعدة البسيطة من Jeff مدير فريق دعم العملاء في شركتنا عندما كنت مهندسًا في هذا القسم. طلب مني Jeff في حال واجهتني مشكلة مع أحد العملاء أن أبحث بنفسي عن حلّ لها لمدة 15 دقيقة، وإن عجزت عن إيجاد الحلّ خلال هذه الفترة أتوجّه حينئذٍ إليه طلبًا للمساعدة. قاعدة الـ 15 دقيقة حاول أن تجد بنفسك حلًّا للمشكلة التي تواجهك ولمدة 15 دقيقة، وإن عجزت بعد هذه الفترة عن إيجاد الحل توجّه إلى شخص آخر طلبًا للمساعدة. يجب عليك إيجاد الحل بنفسك لم تكن غاية Jeff من هذه القاعدة الامتناع عن مساعدتي، بل العكس تماماً، فلو رميت جميع المشاكل التي تواجهني على اﻵخرين دون فهم أسبابها، لن أكون قادرًا حينها على حلّ أي مشكلة بمفردي. تعلّمك الدقائق الخمس عشرة مهارة مهمّة في مجال دعم العملاء، ألا وهي معرفة ما يجب عليك البحث عنه وكيفية إجراء البحث بصورة صحيحة. يجب على كلّ موظف في قسم دعم العملاء أو الفريق الهندسي أن يكون قادرًا على التنقل ضمن الأكواد الأساسية والتوثيقات، ويجب أن يدرك بأنّ الحلّ موجود لو أنّه أخذ الوقت الكافي للبحث عنه. إضافة إلى ما سبق، فإنّ هذه الدقائق الخمس عشرة ستجعلك على اطلاع جيّد بحيثيات المشكلة، ذلك لأنّك قد بحثت خلال هذه الفترة في الأكواد الأساسية، واطلعت على المحادثات السابقة، وفتّشت في محادثات Slack، وتفحّصت التوثيقات الداخلية، ورغم ذلك كله لم تفلح في الوصول إلى الحلّ. ولكن يمكن أن تكون المعلومات التي حصلت عليها في أغلب الأحيان معلومات مهمّة وقيّمة للشخص الذي ستطلب مساعدته، وقد يعينكما ذلك على حلّ المشكلة بسرعة أكبر. ولكن ينبغي عليك طلب المساعدة في بعض اﻷحيان لن تسعفك الدقائق الخمس عشرة في إيجاد الحلّ لمشكلة معينة، وقد لا يسعفك البحث ليوم كامل كذلك. في مثل هذه الحالات، ستجبرك القاعدة على طلب المساعدة. من اليسير جدًّا أن تنغمس إلى أذنيك في حلّ المشكلة، ولكن ينبغي عليك أن تسأل نفسك حينها: “أأنا الشخص المناسب لحلّ هذه المشكلة؟”. يقول المثل: الوقت كالسيف إن لم تقطعه قطعك. قد تشعر بالرضا والفخر بعد أن تبذل مجهودًا كبيرًا في تعلّم أمور جديدة - وستحصل على خبرة كبيرة على المدى الطويل - ولكن لا تتوقع مطلقًا أن تنال الثناء على قضاء ساعات في حلّ مشكلة يمكن لغيرك أن يحلّها في عشر دقائق. كيف يمكن لقاعدة الـ 15 دقيقة أن تساعد الفريق برمّته تقدّم قاعدة الدقائق الخمس عشرة لفرق دعم العملاء أو الفرق الهندسية أو غيرها فوائد جمّة: يتعلّم الموظفون الجدد الاعتماد على أنفسهم. هناك من يستطيع الموظف الجديد الاستعانة به عندما لا يجدّ حلًّا للمشكلة التي يحاول معالجتها. يمكن لهؤلاء الموظفين أن يستشيروا الموظفين القدماء ليتعرفوا على اﻷسلوب الذي يتبعونه في حل المشكلات. يراجع الموظفون القدماء بصورة غير رسمية عمل الفريق ويقدّمون تغذيتهم الراجعة. تزداد خبرة فريق دعم العملاء دون أن يضطر العملاء إلى الانتظار لفترات طويلة للحصول على اﻹجابات. على الرغم من أني لم أعد أعمل مهندسًا (كما أني لست مطّلعًا على جميع التوثيقات)، إلا أنّي ألجأ بصورة منتظمة إلى قاعدة الدقائق الخمس عشرة، فهي تعلّمني احترام وقت زملائي، وتشجّعني في الوقت ذاته على طلب المساعدة عندما أكون محتاجًا إليها. لذا أدعوك لأنّ تجرّب هذه القاعدة وأن تشاركنا النتائج في التعليقات. ترجمة - وبتصرّف - للمقال Know when to ask for help with the 15 Minute Rule لصاحبه Martin Brennan. حقوق الصورة البارزة محفوظة لـ Freepik
  14. إنّ مطالعتك لهذا المقال يعني على الأرجح أنّك قد أتممت الخطوة الأولى في رحلتك كمستقلّ يعمل على شبكة الإنترنت، ألا وهي إيجاد العملاء. وكم نتمنى أن تكون الرحلة قد انتهت عند هذه النقطة، ولكن يؤسفني القول أنّك لا زلت بعيدًا جدًّا عن نقطة النهاية حتى بعد العثور على شخص يرغب في دفع المال لقاء الخدمات التي تقدّمها. بل يمكن القول أنّك الآن تخوض الجزء الأصعب من الرحلة، إذ يجب عليك التعامل مع العملاء مع الحرص على: أن يكون عملاؤك سعداء. أنا لا تصاب بالجنون (وهذه هو الأهمّ، رغم أنّنا ننسى ذلك بعض الأحيان). التعامل مع العملاء أشبه ما يكون بسير البهلوان على الحبل، فمن جانب ترغب في إسعاد عملائك مهما كلّف ذلك، ومن جانب آخر، لا ترغب في أن يتّصل بك العميل عبر 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
  15. هذا هو الجزء الأخير من سلسلة “مدخل إلى إطار العمل 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.