ruby on rails 101 إعادة هيكلة الشيفرة وإضافة نظام استيثاق بسيط


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

هذا هو الجزء الأخير من سلسلة “مدخل إلى إطار العمل 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

  # بقيّة الشيفرة ...

والآن إن حاولت إنشاء مقالة جديدة، ستتلقّى طلب استيثاق كهذا:

challenge.png

جدير بالذكر أنّ هناك العديد من وسائل الاستيثاق في تطبيقات Rails، أشهرها Devise rails engine و Authlogic.

إطار العمل Rails ونظام الترميز UTF-8

إن أسهل طريقة للعمل مع Rails هي تخزين جميع البيانات الخارجية بنظام الترميز UTF-8، وإن لم تفعل ذلك فغالبًا ما تقوم مكتبات Ruby وإطار العمل Rails بتحويل البيانات الأصلية إلى هذا الترميز، ولكن لا يمكن الاعتماد على هذه المكتبات بصورة تامّة، ويفضّل التأكد من أنّ جميع البيانات الخارجية مرمّزة بهذا النظام.

وفي حال حدوث أي خطأ في نظام الترميز فإن الحروف ستظهر في المتصفّح غالبًا على هيئة أشكال معينية سوداء بداخلها علامة استفهام، أو قد تظهر الحروف على هيئة رموز غريبة كأن يظهر الرمز “ü” بدلاً من الحرف “ü”. يتّخذ Rails بعض الإجراءات في نظامه الداخلي للتقليل من المسبّبات الشائعة لهذه المشاكل والتي يمكن الكشف عنها وتصحيحها بصورة تلقائية.

ولكن، إن كنت تتعامل مع بيانات من مصادر خارجية غير مخزّنة بترميز UTF-8، لن يكون Rails قادرًا على الكشف بصورة تلقائية عن أسباب المشكلة أو تقديم حلّ لها.

وهناك مصدران شائعان للبيانات غير المخزّنة بترميز UTF-8:

  1. محرر النصوص: تحفظ معظم محرّرات النصوص الملفات البرمجية بصيغة UTF-8، وإن لم يقم محرّر النصوص الذي تستخدمه في كتابة الشيفرات البرمجية بذلك، فقد ينتج عن ذلك تحوّل الحروف الخاصّة أو حروف اللغات الأخرى غير الإنكليزية إلى التحول في المتصفّح إلى أشكال معينية بداخلها علامة استفهام. ينطبق هذا الأمر كذلك على ملفات الترجمة i18n. تجدر الإشارة إلى أنّه تتيح معظم محررات النصوص التي لا تحفظ الملفات البرمجية بهذا الترميز افتراضيًّا (مثل Dreamweaver) إمكانية تغيير الترميز الافتراضي للملفات المحفوظة إلى نظام UTF-8، وننصح بالقيام بذلك.

  2. قاعدة البيانات: يحوّل Rails البيانات القادمة من قاعدة البيانات إلى ترميز UTF-8، ولكن إن لم يكن هذا نظام الترميز هذا مستخدمًا من طرف قاعدة البيانات فلن يكون بالإمكان تخزين جميع المحارف المدخلة من قبل المستخدم. فعلى سبيل المثال، إن كان نظام الترميز الداخلي لقاعدة البيانات هو Latin-1 وأدخل المستخدم كلمات باللغة الروسية أو العربية أو اليابانية، فستخسر البيانات إلى الأبد بمجرد دخولها إلى قاعدة البيانات. لذا ينصح دائمًا بتحويل نظام الترميز الداخلي في قاعدة البيانات إلى نظام UTF-8.

المصدر:

توثيقات Ruby on Rails.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن