Meet Volt ، إطار روبي واعد للتطبيقات الديناميكية
نشرت: 2022-03-11Volt هو إطار عمل Ruby مصمم للتطبيقات الغنية بالبيانات. تمت كتابة جانبي الخادم والعميل بلغة Ruby (والتي يتم تجميعها بعد ذلك إلى JS باستخدام OPAL) ، مما يسمح للمطور بكتابة تطبيقات ديناميكية للغاية دون الحاجة إلى كتابة سطر واحد من كود Javascript. إذا كنت من محبي روبي مثلي ، فستحب هذا الإطار.
في محاولة لجعل تطبيقات الويب أكثر ديناميكية ، اكتسبت إطارات جافا سكريبت الأمامية مثل Angular.js و Backbone.js و Ember.js شهرة كبيرة. ومع ذلك ، غالبًا ما تتطلب هذه الأطر تطبيقًا خلفيًا ليكون مفيدًا ، لذلك يتم استخدامها جنبًا إلى جنب مع أطر الويب مثل Ruby on Rails و Django.
من ناحية أخرى ، فإن إطار روبي Volt قادر على إدارة الواجهة الخلفية والواجهة الأمامية الديناميكية. نظرًا لأن كلتا الوظيفتين مدمجتان بإحكام في جوهرها (في الواقع ، فإن Volt تشبه إلى حد كبير بنية MVVM ، حيث تستفيد من مزايا روابط البيانات) ، فهي تمكن المطور من بناء هذه التطبيقات بسرعة.
ميزة رائعة جدًا تخرج من الصندوق هي ميزة Volt في الوقت الفعلي. إذا سبق لك إنشاء تطبيقات في الوقت الفعلي ، فأنت تعلم أن العملية قد تكون صعبة - ربما تكون قد نفذت استطلاعات AJAX أو مقابس الويب أو الأحداث المرسلة من الخادم (SSE) أو حتى استخدمت خدمات خارجية ، مما زاد من تعقيد التطبيق وحتى تكبدت تكاليف إضافية . على عكس الأطر الأخرى ، يحافظ Volt على الاتصال بالخادم على قيد الحياة (عبر مآخذ الويب) ، لذلك بدلاً من تقديم طلبات Ajax لكل إجراء ، فإنه يدفع التغييرات على الفور إلى جميع العملاء. ليس هناك حاجة إلى التكوين لهذا العمل.
باستخدام Volt لإنشاء تطبيق دردشة
في هذا البرنامج التعليمي لإطار عمل Ruby ، سأوجهك خلال عملية إنشاء تطبيق في الوقت الفعلي باستخدام Volt ، وما هي أفضل طريقة من تطبيق الدردشة لإثبات قدراته ، حيث تظل الدردشة هي حالة الاستخدام الأولى لتطبيقات الوقت الفعلي.
بادئ ذي بدء ، دعنا نثبت Volt و MongoDB. لن يتم تغطية العملية الأخيرة بالتفصيل:
gem install volt brew install mongodb
mkdir -p /data/db
(إنشاء dbpath)
chown `id -u` /data/db (change the owner to have the proper dbpath permissions)
نحن الآن جاهزون لإنشاء تطبيقنا الأول ، لنسميه "الدردشة". يمكننا القيام بذلك بسهولة في سطرين:
volt new chat cd chat
هيكل الوثيقة له بعض أوجه التشابه مع ريلز. الاختلاف الرئيسي الذي سيلاحظه مستخدمو ريلز هو أن لدينا مجلدًا إضافيًا داخل التطبيق يحتوي على بقية المجلدات مثل الأصول ووحدات التحكم والنماذج وطرق العرض ، وهذا المجلد الإضافي هو "مكون".
المكوّن هو قسم منفصل من التطبيق. يتم عرض جميع الصفحات الموجودة داخل أحد المكونات دون إعادة تحميل الصفحة نظرًا لأن جميع ملفات هذا المكون يتم تحميلها بطلب http الأولي ، لذلك إذا قمنا بزيارة صفحة مكونة مختلفة ، فسيتم إجراء طلب http جديد وستتم إعادة تحميل الصفحة ". في هذا المثال ، دعنا نستخدم المكون الافتراضي المسمى "main".
لنبدأ الخادم بتنفيذ أمر "volt server" في وحدة التحكم ، ونرى كيف يبدو في المتصفح من خلال الانتقال إلى localhost: 3000:
volt server
لا تنس أيضًا بدء تشغيل MongoDB في وحدة التحكم:
mongod
يمكننا أن نلاحظ أن Volt يأتي مع عدد من الصفحات الافتراضية ، بما في ذلك "الصفحة الرئيسية" و "حول". يمكن تخصيصها على الفور.
الشيء الآخر الجدير بالذكر هو زر تسجيل الدخول في أعلى الجانب الأيمن من الصفحة. يحتوي Volt على وظيفة "مستخدم" مدمجة في الإطار عبر جوهرة "volt-user-Templates" ، والتي توفر طريقة لتسجيل المستخدمين والمصادقة عليهم ، فور إخراجها من الصندوق.
ابدء
الآن ، لنبدأ العمل على تطبيقنا. بادئ ذي بدء ، لا نحتاج إلى صفحة "حول" حتى نتمكن من المضي قدمًا وحذف ما يلي: ملف app/main/views/main/about.html
، الإجراء المتعلق بالإجراء في app/main/controllers/main_controller.rb
، قم بإزالة المسار /about
في app/main/config/routes.rb
التنقل في app/main/views/main/main.html
.
<ul class="nav nav-pills pull-right"> <:nav href="/" text="Home" /> <:user-templates:menu /> </ul>
الآن دعنا نبدأ العمل ونبدأ بإدراج جميع المستخدمين المسجلين:
<:Body> <h1>Home</h1> <div class="row"> <div class="col-md-4"> {{ _users.each do |user| }} <div class="contact"> {{user._name}} </div> {{ end }} </div> </div>
الآن يتم سرد جميع المستخدمين المسجلين في الصفحة الرئيسية. لاحظ أن الكود المكتوب داخل {{}} هو كود روبي الذي يتم تنفيذه. بهذه الطريقة يمكننا تكرار مجموعة المستخدمين وطباعة كل منها.
كما لاحظت ، "المستخدمين" هو اسم المجموعة حيث يتم تخزين جميع المستخدمين ؛ شيء يجب مراعاته هو أنه يتم الوصول إلى السمات بشرطة سفلية ''
مضافة إلى اسم السمة. لكي يعمل هذا ، نحتاج أولاً إلى إضافة سطر من التعليمات البرمجية في الجزء العلوي من ملف main_controller.rb
:
model :store
يأتي Volt مع نماذج تجميع متعددة يمكن الوصول إليها من وحدة التحكم ، ويخزن كل منها المعلومات في مكان مختلف. يخزن نموذج جمع المتجر البيانات في مخزن البيانات ، وهنا نحدد وحدة التحكم لاستخدام ذلك (مخزن البيانات الوحيد المدعوم حاليًا هو MongoDB). لنقم بإنشاء اثنين من المستخدمين لنرى كيف يبدو.
في الوقت الحالي ، لا يوجد شيء مثير بخصوص هذه الصفحة ، نحن فقط ندرج المستخدمين المسجلين. الآن أود أن أكون قادرًا على تحديد مستخدم لإرسال رسالة إليه ، وإزالة اسم المستخدم المسجل حاليًا من القائمة (نظرًا لأنه لا ينبغي أن يكون قادرًا على إرسال رسائل إلى نفسه) ، اعرض القائمة فقط للمصادقة المستخدمين وعرض صفحة "مقصودة" للمستخدمين غير المصادق عليهم:
<:Body> <h1>Home</h1> {{ if Volt.user }} <div class="row"> <div class="col-md-4"> {{ _users.each do |user| }} {{ if user._id != Volt.user._id }} <div class="contact {{ if params._user_id == user._id }} active {{ end }}" e-click="select_conversation(user)"> {{user._name}} </div> {{ end }} {{ end }} </div> </div> {{ else }} <p>This is a sample application built with Volt to demonstrate its real-time capabilities. Please log in to access it.</p> {{ end }}
يقوم Volt.user بإرجاع المستخدم الحالي (الذي قام بتسجيل الدخول) أو لا شيء.

تتيح لنا سمة النقر الإلكتروني تحديد طريقة من وحدة التحكم والتي سيتم استدعاؤها عند النقر فوق هذا العنصر.
السمات و CSS
في الواقع ، جميع سمات "e-" هي مجلدات أحداث في Volt ، لذلك على سبيل المثال يمكننا إضافة إرسال إلكتروني إلى نموذج لاختيار الإجراء الذي سيتم استدعاؤه على وحدة التحكم. سنقوم بإضافة معرف المستخدم "المحدد" إلى المعلمات حتى نتمكن من معرفة أي واحد تم تحديده وإضافة فئة تسمى "نشطة" والتي يمكننا تصميمها لاحقًا.
لنقم الآن بإنشاء طريقة select_conversation
في وحدة التحكم:
def select_conversation(user) params._user_id = user._id end
وهذا كل شيء - إذا قمت بفحص الصفحة مرة أخرى ، يمكنك أن ترى أن عنوان URL يتغير في كل مرة تنقر فيها على اسم المستخدم. أيضًا ، تتم إضافة الفئة "active" إلى هذا العنصر ، لذلك دعونا نضيف بعض CSS لجعله مرئيًا (سأمضي قدمًا وأضيف CSS للعناصر التي سنضيفها لاحقًا):
.conversation{ form{ input{ margin: 10px 0 5px 0; } } }
.contact{ width:100%; padding:5px; margin: 4px 0; font-size:15px; cursor:pointer; &:hover{ background-color: #FAFAFA; } &.active{ background-color: #337ab7; color: #FFF; } .badge{ background-color: #900; } }
.message{ max-width: 80%; padding:10px 15px; margin: 5px 0; background-color: #FEFEFE; border: 1px solid #E7E7E7; border-radius: 5px; float: left; clear:both; &.sent{ background-color: #E4F3DB; border: 1px solid #B7D0A7; float: right; } p{ margin:0; } }
لنقم الآن بإنشاء نموذج على الجانب الأيمن لإرسال رسائل إلى كل مستخدم:
<:Body> <h1>Home</h1> {{ if Volt.user }} <div class="row"> <div class="col-md-4"> {{ _users.each do |user| }} {{ if user._id != Volt.user._id }} <div class="contact {{ if params._user_id == user._id }} active {{ end }}" e-click="select_conversation(user)"> {{user._name}} </div> {{ end }} {{ end }} </div> {{ if params._user_id }} <div class="col-md-8 well conversation"> {{ current_conversation.each do |message| }} <div class="message {{ if message._sender_id == Volt.user._id }} sent {{ end }}"> <p>{{ message._text }}</p> </div> {{ end }} {{ if current_conversation.count == 0 }} <p>You have no messages yet. Start chatting!</p> {{ else }} <div class="clearfix"></div> {{ end }} <form e-submit="send_message" role="form"> <div class="form-group"> <input class="form-control" type="text" placeholder="Write a message" value="{{ page._new_message }}" /> <button type="submit" class="btn btn-primary pull-right">Submit</button> </div> </form> </div> {{ end }} </div> {{ else }} <p>This is a sample application built with Volt to demonstrate its real-time capabilities. Please log in to access it.</p> {{ end }}
أولاً ، نتحقق مما إذا كان هناك مستخدم محدد قبل عرض النموذج ، ثم نعرض جميع الرسائل من المحادثة الحالية (المحادثة مع المستخدم المحدد) من طريقة في وحدة التحكم التي سنقوم بتعريفها بعد قليل ، وفي الجزء السفلي نعرض نموذجًا لإرسال رسائل جديدة.
لاحظ أن قيمة الإدخال هي سمة نقوم بإنشائها في نموذج مجموعة الصفحات لأننا لا نريد تخزينها في مخزن البيانات. الآن دعنا نحدد طريقتين current_conversation
و send_message
في وحدة التحكم:
def send_message unless page._new_message.strip.empty? _messages << { sender_id: Volt.user._id, receiver_id: params._user_id, text: page._new_message } page._new_message = '' end end def current_conversation _messages.find({ "$or" => [{ sender_id: Volt.user._id, receiver_id: params._user_id }, { sender_id: params._user_id, receiver_id: Volt.user._id }] }) end
في طريقة send_message ، نضيف رسالة جديدة إلى المجموعة إذا لم تكن الرسالة فارغة (نحن نتحقق مضمنة حتى لا نضطر إلى العبث بعمليات التحقق من الصحة في الوقت الحالي) ، ثم قمنا بتعيين الصفحة ._new_message to ''
نقوم بإفراغ حقل الإدخال.
قد نرغب في إضافة هذا السطر إلى نهاية طريقة select_conversation
أيضًا. تقوم طريقة المحادثة الحالية فقط بالاستعلام عن مجموعة _messages
للرسائل بين المستخدم المحدد والمستخدم الحالي.
اختتم الإخطارات في الوقت الفعلي
للإنهاء ، أرغب في الحصول على نوع من نظام الإشعارات ، حتى يتمكن المستخدمون من معرفة متى يقوم المستخدمون الآخرون بمراسلتهم.
دعنا نضيف مجموعة جديدة تسمى _notifications
مجموعة جديدة بعد إرسال كل رسالة:
def send_message unless page._new_message.strip.empty? _messages << { sender_id: Volt.user._id, receiver_id: params._user_id, text: page._new_message } _notifications << { sender_id: Volt.user._id, receiver_id: params._user_id } page._new_message = '' end end def select_conversation(user) params._user_id = user._id unread_notifications_from(user).then do |results| results.each do |notification| _notifications.delete(notification) end end page._new_message = '' end def unread_notifications_from(user) _notifications.find({ sender_id: user._id, receiver_id: Volt.user._id }) end
نحتاج أيضًا إلى حذف الإشعارات من بعد تحديد المستخدم للمحادثة ورؤية الرسائل الجديدة ، لذلك أضفت هذا الجزء إلى طريقة select_conversation
.
دعنا نضيف عداد إشعار بجوار اسم المستخدم:
<div class="contact {{ if params._user_id == user._id }} active {{ end }}" e-click="select_conversation(user)"> {{user._name}} {{ if unread_notifications_from(user).count > 0 }} <span class="badge"> {{ unread_notifications_from(user).count }} </span> {{ end }} </div>
الآن أصبح التطبيق جاهزًا ، يمكنك فتح مستعرضين والبدء في اختبار إمكانيات Volt في الوقت الفعلي.
فولت بالتأكيد يستحق المحاولة
على الرغم من أن إطار Volt ليس ناضجًا وقويًا مثل معظم أطر Ruby الشائعة التي كانت موجودة منذ سنوات (في لحظة Volt لا تزال في مرحلة تجريبية) ، إلا أنها تستحق الدراسة والدراسة.
إذا كنت مهتمًا ، فاستخدم هذا البرنامج التعليمي لإطار عمل Ruby لإخراج Volt في جولة. راقب المزيد من التطورات ، حيث يبدو Volt كإطار عمل Ruby واعد جدًا حتى في هذه المرحلة المبكرة من التطوير.
هناك الكثير من الميزات الجديدة الرائعة في طور الإعداد وأنا متأكد تمامًا من أن Volt ستصبح أكثر صلة خلال العامين المقبلين ، حيث يبدأ المزيد من الأشخاص في تجربتها. نظرًا لعدد من الميزات المبتكرة ، قد يقع العديد من المطورين في حب Volt ويستخدمونه في مشروع Ruby التالي.