<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Ruby on Rails</title><link>https://academy.hsoub.com/programming/ruby/rails/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Ruby on Rails</description><language>ar</language><item><title>&#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x625;&#x637;&#x627;&#x631; Ruby on Rails &#x641;&#x64A; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; &#x644;&#x64A;&#x646;&#x643;&#x633;</title><link>https://academy.hsoub.com/programming/ruby/rails/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-ruby-on-rails-%D9%81%D9%8A-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-%D9%84%D9%8A%D9%86%D9%83%D8%B3-r2114/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_09/------rbenv--.png.6fe957eae6d28e43faa3e1a59dfbbfee.png" /></p>
<p>
	يعد <a href="https://wiki.hsoub.com/Rails" rel="external">روبي أون ريلز Ruby on Rails</a> -أو اختصارًا ريلز Rails- من أشهر أطر العمل بلغة روبي Ruby المستخدمة في تطوير المواقع وتطبيقات الويب بسهولة وسرعة، إذ يمكن تثبيت إطار العمل باستخدام أداة سطر الأوامر <a href="https://github.com/rbenv/rbenv" rel="external nofollow">rbenv</a>، التي تتيح إمكانية إنشاء بيئة لتطوير التطبيقات باستخدام روبي أون ريلز والتبديل بين نسخ روبي المختلفة، كما تمكّنك من تخصيص وتحديد نسخة روبي مختلفة لكل تطبيق تطوره على حدى بغض النظر عن النسخة الافتراضية العامة ضمن النظام، كما تمكّنك من تحديد نسخة روبي محددة لكل مستخدم على حدى مع ترك إمكانية تغيير تلك النسخة باستخدام متغيرات البيئة.
</p>

<p>
	سنتعرف في هذا المقال على طريقة تثبيت روبي أون ريلز باستخدام rbenv و gem، إذ سنبدأ بتثبيت الحزم المطلوبة لعمل rbenv ثم روبي وبعدها سنثبت الإضافة ruby-build لنتمكن من تثبيت أحد إصدارات روبي المتوفرة. بعد ذلك، سنستخدم gem لتثبيت إطار ريلز لنتمكن من استخدام روبي ضمنه من أجل <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8/" rel="">تطوير تطبيقات الويب</a>، وسنتعلم أيضًا طريقة التحقق من توفر التحديثات لنسخة rbenv المثبتة، وطريقة إزالة تثبيت نسخ روبي وأيضًا rbenv.
</p>

<p>
	ستحتاج لتطبيق الخطوات في هذا المقال إلى ما يلي:
</p>

<ul>
	<li>
		نظام خادم أوبنتو 22.04 مثبت مع إمكانية الوصول لحساب مستخدم يمكنه تنفيذ الأمر <code>sudo</code> وجدار ناري مثبت.
	</li>
	<li>
		نسخة <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A3%D9%88%D9%84-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-nodejs-%D9%88%D8%AA%D9%86%D9%81%D9%8A%D8%B0%D9%87-r1711/" rel="">نود Node.js</a> مثبتة على النظام، إذ تحتاج بعض مزايا ريلز، مثل ميزة أنبوب الموارد Asset Pipeline لبيئة تشغيل جافا سكريبت لعملها.
	</li>
</ul>

<h2>
	تثبيت أداة rbenv واعتماديتها
</h2>

<p>
	تعتمد <a href="https://academy.hsoub.com/programming/ruby/" rel="">لغة روبي</a> على عدد من الحزم التي يمكنك تثبيتها من خلال مدير الحزم، وحالما تثبّت هذه الحزم، يمكنك تثبيت rbenv واستخدامها لتثبيت روبي.
</p>

<p>
	نبدأ بتنفيذ أمر تحديث قائمة الحزم على النظام:
</p>

<pre class="ipsCode">$ sudo apt update
</pre>

<p>
	ثم نثبّت الاعتماديات المطلوبة تثبيت روبي:
</p>

<pre class="ipsCode">$ sudo apt install git curl libssl-dev libreadline-dev zlib1g-dev autoconf bison build-essential libyaml-dev libreadline-dev libncurses5-dev libffi-dev libgdbm-dev
</pre>

<p>
	بعد ذلك، يمكننا تثبيت rbenv باستخدام الأمر <code>curl</code> لتنزيل النص البرمجي المستخدم لتثبيته الموجود على غيت هب GitHub وتمريره مباشرةً إلى الأمر <code>bash</code> لتنفيذه على النحو التالي:
</p>

<pre class="ipsCode">$ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-installer | bash
</pre>

<p>
	نضيف المسار "rbenv/bin./~" إلى المتغير <code>PATH$</code> لنتمكن من استخدام أداة سطر الأوامر rbenv، وذلك بتعديل الملف bashrc./~ ليُطبق التعديل ضمن جلسات الطرفية اللاحقة:
</p>

<pre class="ipsCode">$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' &gt;&gt; ~/.bashrc
</pre>

<p>
	ثم نضيف أمر تحميل rbenv إلى نفس الملف مجددًا على النحو التالي:
</p>

<pre class="ipsCode">$ echo 'eval "$(rbenv init -)"' &gt;&gt; ~/.bashrc
</pre>

<p>
	ولتطبيق تلك التعديلات على جلسة الطرفية الحالية ننفذ الأمر التالي:
</p>

<pre class="ipsCode">$ source ~/.bashrc
</pre>

<p>
	نستخدم الأمر type لنتأكد من تطبيقها وتوفر الأمر rbenv، إذ سيعرض هذا الأمر معلومات حول rbenv على النحو التالي:
</p>

<pre class="ipsCode">$ type rbenv
</pre>

<p>
	ليظهر لنا الخرج التالي:
</p>

<pre class="ipsCode">rbenv is a function
rbenv ()
{
    local command;
    command="${1:-}";
    if [ "$#" -gt 0 ]; then
        shift;
    fi;
    case "$command" in
        rehash | shell)
            eval "$(rbenv "sh-$command" "$@")"
        ;;
        *)
            command rbenv "$command" "$@"
        ;;
    esac
}
</pre>

<p>
	وبذلك نكون ثبتنا كلًا من الأداتين rbenv و ruby-build، وسنبدأ في الفقرة التالية بتثبيت روبي.
</p>

<h2>
	تثبيت روبي باستخدام ruby-build
</h2>

<p>
	بعد أن ثبتنا الإضافة ruby-build، يمكننا تثبيت أي نسخة من روبي نحتاجها عبر سطر الأوامر ونبدأ بعرض النسخ المتاحة بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode">$ rbenv install -l
</pre>

<p>
	ليظهر لنا قائمة بالنسخ المتوفرة:
</p>

<pre class="ipsCode">2.7.7
3.0.5
3.1.3
3.2.0
jruby-9.4.0.0
mruby-3.1.0
picoruby-3.0.0
truffleruby-22.3.1
truffleruby+graalvm-22.3.1

Only latest stable releases for each Ruby implementation are shown.
Use 'rbenv install --list-all / -L' to show all local versions.
</pre>

<p>
	لنختار نسخة روبي 3.2.0 ونثبتها كما يلي:
</p>

<pre class="ipsCode">$ rbenv install 3.2.0
</pre>

<p>
	تستغرق عملية التنزيل والتثبيت بعض الوقت لإنهائها، وبعد ذلك يمكننا تعيين تلك النسخة على أنها نسخة افتراضية باستخدام الأمر الفرعي <code>global</code> على النحو التالي:
</p>

<pre class="ipsCode">$ rbenv global 3.2.0
</pre>

<p>
	ونتحقق من ذلك بعرض نسخة روبي الحالية:
</p>

<pre class="ipsCode">$ ruby -v
</pre>

<p>
	ليظهر لنا معلومات النسخة التي اخترناها سابقًا على النحو التالي:
</p>

<pre class="ipsCode">$ ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux]
</pre>

<p>
	وبذلك نكون قد ثبتنا نسخة من نسخ روبي وعيناها على أنها نسخة عامة افتراضية وأصبحت جاهزة للعمل عليها. سنعد في الفقرة التالية مكتبة gems وإطار ريلز
</p>

<h2>
	التعامل مع المكتبات Gems
</h2>

<p>
	الطريقة التي تنشر بها مكتبات روبي تسمى <a href="https://academy.hsoub.com/questions/5623-%D9%85%D8%A7-%D9%87%D9%88-%D8%B1%D9%88%D8%A8%D9%8A-gem%D8%9F/?sortby=date" rel="">gems</a> ويمكن استخدام الأمر <code>gem</code> لإدارتها وأيضًا لتثبيت إطار ريلز، فعند تثبيت أي مكتبة منها ينشأ لها ملفات توثيق محلي، وقد تستغرق تلك العملية وقتًا لذا يمكننا إلغاؤها بإنشاء ملف إعدادات في المجلد "gemrc./~" وإضافة تعليمة ضمنه بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode">$ echo "gem: --no-document" &gt; ~/.gemrc
</pre>

<p>
	ونبدأ بتثبيت أول أداة وهي <a href="https://bundler.io/" rel="external nofollow">Bundler</a>، التي تفيد في إدارة الاعتماديات ضمن المشروع ويعتمد عليها إطار ريلز في عمله:
</p>

<pre class="ipsCode">$ gem install bundler
</pre>

<p>
	ليظهر لنا الخرج التالي:
</p>

<pre class="ipsCode">Fetching bundler-2.4.5.gem
Successfully installed bundler-2.4.5
1 gem installed
</pre>

<p>
	يمكننا استخدام الأمر <code>gem env</code> (الأمر الفرعي <code>env</code> هو اختصار للأمر <code>environment</code>)، لعرض معلومات عن البيئة والاعدادات الحالية للمكتبات gems، إذ يمكننا مثلًا عرض مسار تثبيت الاعتماديات على النظام بتنفيذ الأمر الفرعي <code>home</code> على النحو التالي:
</p>

<pre class="ipsCode">$ gem env home
</pre>

<p>
	ليظهر لنا المسار على النحو التالي:
</p>

<pre class="ipsCode">/home/hassan/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0
</pre>

<p>
	بعد أن ثبتنا gems يمكننا الآن تثبيت إطار ريلز وهو ما سنشرحه في الفقرة التالية.
</p>

<h2>
	تثبيت ريلز
</h2>

<p>
	لتثبيت ريلز نُنفذ الأمر <code>gem install</code> مع الخيار <code>v-</code> لتحديد الإصدار المطلوب إذ سنستخدم في هذا المقال الإصدار 7.0.4:
</p>

<pre class="ipsCode">$ gem install rails -v 7.0.4
</pre>

<p>
	يُثبت الأمر السابق المكتبة التي حددناها مع اعتمادياتها، وبما أن ريلز إطار عمل لتطوير تطبيقات الويب المعقدة لذا فهو يحتوي على العديد من الاعتماديات، وهو سبب استغراق تنفيذ الأمر السابق بعض الوقت وسينتج عنه رسالة تفيد بتثبيت ريلز بنجاح مع اعتمادياته:
</p>

<pre class="ipsCode">...
Successfully installed rails-7.0.4
35 gems installed
</pre>

<p>
	يمكننا استعراض الإصدارات المتاحة لاختيار تثبيت إصدار مختلف من ريلز عن طريق البحث باستخدام الأمر <code>search</code>، الذي سيعرض قائمة بالإصدارات المتاحة للتنزيل، ويمكننا الاختيار منها وتثبيت أحد تلك الإصدارات، ففي الأمر التالي سنختار الإصدار 4.2.7:
</p>

<pre class="ipsCode">$ gem search '^rails$' --all
$ gem install rails -v 4.2.7
</pre>

<p>
	وإذا أردنا تثبيت أحدث إصدار من ريلز يمكننا تنفيذ نفس الأمر لكن بدون تحديد رقم الإصدار:
</p>

<pre class="ipsCode">$ gem install rails
</pre>

<p>
	إذ سيُنشئ rbenv مجلدًا لملفات shims، الذي يشير إلى الملفات المستخدمة من قبل إصدار روبي المُفعل حاليًا. يدير rbenv من خلال الأمر الفرعي rehash ملفات shims ضمن ذلك المجلد، وذلك لمطابقة كل أمر من أوامر روبي عبر كل إصدار مثبت من روبي على الجهاز الخاص بنا. عند تثبيت إصدار جديد من روبي أو مكتبة gem توفر أوامرًا يمكن تنفيذها مثل ريلز، يجب تنفيذ الأمر التالي:
</p>

<pre class="ipsCode">$ rbenv rehash
</pre>

<p>
	للتحقق من تثبيت ريلز بنجاح يمكنك طباعة رقم إصداره باستخدام الأمر التالي:
</p>

<pre class="ipsCode">$ rails -v
</pre>

<p>
	فإذا انتهى التثبيت بنجاح سيظهر لنا رقم إصدار ريلز المُثبت:
</p>

<pre class="ipsCode">Rails 7.0.4
</pre>

<p>
	الآن، يمكننا البدء في اختبار وتثبيت روبي ضمن ريلز وتطوير تطبيقات الويب باستخدامه، وسنستعرض في الفقرة التالية طريقة تحديث rbenv لآخر نسخة متوفرة.
</p>

<h2>
	تحديث rbenv
</h2>

<p>
	بما أننا ثبتنا rbenv يدويًا باستخدام Git، يمكننا تحديثه لآخر إصدار باستخدام الأمر <code>git pull</code> ضمن المجلد rbenv./~ على النحو التالي:
</p>

<pre class="ipsCode">$ cd ~/.rbenv
$ git pull
</pre>

<p>
	وبذلك نتأكد من استخدام أحدث إصدار متاح من rbenv.
</p>

<h2>
	إلغاء تثبيت إصدارات روبي
</h2>

<p>
	قد تتراكم الإصدارات الإضافية التي قد ننزلها من روبي ضمن المجلد "rbenv/versions./~"، ولحل تلك المشكلة يمكننا استخدام الأمر الفرعي <code>uninstall</code> الذي توفره الإضافة <code>ruby-build</code> لإزالة الإصدارات السابقة التي لا نحتاج لها، فمثلًا يمكن استخدام الأمر التالي لإلغاء تثبيت إصدار روبي بنسخة 3.2.0:
</p>

<pre class="ipsCode">$ rbenv uninstall 3.2.0
</pre>

<p>
	يفيد استخدام أمر إلغاء تثبيت الذي يوفره rbenv بتنظيف ذلك المجلد وإزالة الإصدارات القديمة من روبي لنبقي فقط على ما نحتاج لاستخدامه حاليًا.
</p>

<h2>
	إلغاء تثبيت rbenv
</h2>

<p>
	يمكننا إزالة rbenv من نظام التشغيل في حال عدم الحاجة لاستخدامه، وذلك بفتح الملف "bashrc./~" ضمن أي محرر للنصوص مثل نانو nano على النحو التالي:
</p>

<pre class="ipsCode">$ nano ~/.bashrc
</pre>

<p>
	ونبحث عن السطرين التاليين ونحذفهما من الملف:
</p>

<pre class="ipsCode">...
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
</pre>

<p>
	بعد حذف هذين السطرين نحفظ الملف ونخرج من المحرر بالضغط على المفتاحين "CTRL + X" ثم "Y" و "Enter" لتأكيد حفظ الملف، ويمكننا بعدها إزالة rbenv وجميع إصدارات روبي المثبتة باستخدام الأمر التالي:
</p>

<pre class="ipsCode">$  rm -rf `rbenv root`
</pre>

<p>
	ستطبق هذه التغييرات ضمن الجلسة بعد تسجيل الخروج وتسجيل الدخول مرة أخرى.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تعلمنا في هذا المقال كيفية تثبيت rbenv والأمر gem لتثبيت إطار عمل <a href="https://academy.hsoub.com/programming/ruby/rails/" rel="">روبي أون ريلز</a> كاملًا، وبذلك يمكننا إنشاء مشاريع تطوير تطبيقات الويب الجديدة.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-ruby-on-rails-with-rbenv-on-ubuntu-22-04" rel="external nofollow">How To Install Ruby on Rails with rbenv on Ubuntu 22.04</a> لأصحابه Brian Hogan و Lisa Tagliaferri و Jeanelle Horcasitas.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/ruby/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%B1%D9%88%D8%A8%D9%8A-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-%D9%84%D9%8A%D9%86%D9%83%D8%B3-r2113/" rel="">تثبيت روبي وإعداد بيئة برمجة محلية في أوبنتو لينكس</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/ruby/rails/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-ruby-on-rails-r526/" rel="">مدخل إلى إطار العمل Ruby on Rails</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/ruby/%D9%83%D9%84-%D9%85%D8%A7-%D8%AA%D8%AD%D8%AA%D8%A7%D8%AC-%D8%A5%D9%84%D9%8A%D9%87-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%80-ruby-r16/" rel="">كل ما تحتاج إليه لتعلم البرمجة بـ Ruby</a>
	</li>
	<li>
		<a href="https://wiki.hsoub.com/Rails" rel="external">توثيق روبي أون ريلز العربي</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2114</guid><pubDate>Sun, 10 Sep 2023 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x62B;&#x628;&#x64A;&#x62A; Ruby on Rails &#x645;&#x639; rbenv &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 18.04</title><link>https://academy.hsoub.com/programming/ruby/rails/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-ruby-on-rails-%D9%85%D8%B9-rbenv-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1804-r843/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_03/How-To-Install-Ruby-on-Rails.jpg.6a57f0595ec0df81ec8e80ae5719dd82.jpg" /></p>

<p>
	ريلز أو Ruby on Rails هو أحد أكثر الإطارات المعروفة للمطورين الذين يتطلعون إلى إنشاء مواقع وتطبيقات ويب، التي تجمع بين لغة برمجة روبي مع إطار العمل ريلز framework Rails مما جعل إنشاء التطبيقات الويب أكثر بساطة.
</p>

<p>
	لتثبيت ريلز يمكنك استخدام أداة سطر الأوامر rbenv التي ستوفر لك بيئة صلبة لتطوير تطبيقات ريلز تتيح لك التبديل بسهولة بين إصدارات Ruby و إبقاء فريقك بأكمله على نفس الاصدار. توفر لك rbenv دعما لتحديد اصدارات روبي الخاصة بالتطبيق وتغيرها لكل مستخدم، كما تسمح لك باستخدام متغير لإعادة تحديد إصدار روبي.
</p>

<p>
	سوف يوضح لك هذا المقال عملية تثبيت ريلز باستخدام rbenv.
</p>

<p>
	## المتطلبات الأساسية
</p>

<p>
	من أجل متابعة هذا المقال تحتاج إلى:
</p>

<ul>
<li>
		إعداد خادم اوبنتو 18.04 و تملك مستخدم غير جذري (non-root) يملك صلاحيات sudo و مثبت عليه جدار حماية. يمكنك اعداده بالعودة إلى مقال <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">الإعداد الأولي لخام اوبنتو</a>
	</li>
	<li>
		قم بثبيت Node.js باستخدام official PPA كما هو موضح في <a href="https://academy.hsoub.com/devops/linux/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-nodejs-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D8%A3%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r419/" rel="">كيفية تثبيت Node.js على 18.04 اوبنتو</a> إذ تعتمد بعض ميزات ريلز مثل خط <a href="https://wiki.hsoub.com/Rails/asset_pipeline" rel="external">أنابيب الأصول Asset Pipeline</a> و<a href="https://wiki.hsoub.com/Rails/working_with_javascript_in_rails" rel="external">مُشغل جافاسكربت الآني runtime JavaScript</a> على ما يوفره Node.js.
	</li>
</ul>
<h3>
	الخطوة الأولى: تثبيت rbenv ومتطلباته
</h3>

<p>
	تعتمد Ruby على عدة حزم يمكنك تثبيتها من خلال apt-get وبمجرد تثبيتها يمكنك تثبيت rbenv واستخدامه لتثبيت روبي.
</p>

<p>
	أولاً، قم بتحديث قائمة الحزمة الخاصة بك:
</p>

<pre class="ipsCode">
 $ sudo apt update 
</pre>

<p>
	من قم بتثبيت المتطلبات اللازمة لتشغيل روبي بتنفيذ الأمر التالي .
</p>

<pre class="ipsCode">
$ sudo apt install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm5 libgdbm-dev
</pre>

<p>
	بمجرد الانتهاء من تثبيت المتطلبات يمكنك البدء بتثبيت rbenv من GitHub ووضعه داخل المجلد rbenv ./~:
</p>

<pre class="ipsCode">
$ git clone https://github.com/rbenv/rbenv.git ~ / .rbenv 
</pre>

<p>
	بعد ذلك لابد من تعريف <code>PATH$</code> الخاص بك على <code>rbenv</code> لاستخدامها في واجهة سطر الأوامر ويكون ذلك بإضافة الملف <code>rbenv/bin./~</code> إلى <code>PATH$</code> الخاص بك داخل الملف <code>bashrc./~</code> ولكن تذكر من أجل ظهور التغيرات لابد من إنهاء ومن ثم إعادة تشغيل واجهة سطر الأوامر؛ انظر للأمر التالي:
</p>

<pre class="ipsCode">
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' &gt;&gt; ~/.bashrc 
</pre>

<p>
	الآن أضف الأمر <code>"(-eval "$(rbenv init</code> إلى الملف <code>bashrc./~</code> من أجل أن يتم تجميل rbenv تلقائيا:
</p>

<pre class="ipsCode">
$ echo 'eval "$(rbenv init -)"' &gt;&gt; ~/.bashrc
</pre>

<p>
	لتطبيق التغييرات التي أجرتها على الملف <code>bashrc./~</code> على جلسة الصدفة shell الحالية نفذ الأمر التالي:
</p>

<pre class="ipsCode">
$ source ~/.bashrc
</pre>

<p>
	للتحقق من إعدادات <code>rbenv</code> أنه تم تثبيتها بشكل صحيح استخدم الأمر type الذي سيعرض المزيد من المعلومات حول <code>rbenv</code>:
</p>

<pre class="ipsCode">
$ type rbenv
</pre>

<p>
	سوف يعرض الأمر ما يلي:
</p>

<pre class="ipsCode">
rbenv is a function
rbenv ()
{
    local command;
    command="${1:-}";
    if [ "$#" -gt 0 ]; then
        shift;
    fi;
    case "$command" in
        rehash | shell)
            eval "$(rbenv "sh-$command" "$@")"
        ;;
        *)
            command rbenv "$command" "$@"
        ;;
    esac
}
</pre>

<p>
	بعد ذلك قم بتنزيل <code>ruby-build</code> وهو عبارة عن إضافة plugin، إذ تضيف الأمر <code>rbenv install</code> الذي يسهل عملية تنزيل الإصدارات الجديدة من روبي:
</p>

<pre class="ipsCode">
$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
</pre>

<p>
	في هذه المرحلة تم تثبيت كل من rbenv و ruby-build لنبدأ الآن بتثبيت روبي:
</p>

<h2>
	الخطوة الثانية: تثبيت روبي مع ruby-build
</h2>

<p>
	بعد تثبيت <code>ruby-build</code> يمكنك الآن تثبيت إصدارات روبي التي تحتاج بأمر بسيط. اولا سنعرض جميع الإصدارت المتاحة من روبي:
</p>

<pre class="ipsCode">
$ rbenv install -l
</pre>

<p>
	ستظهر لك قائمة كبيرة من الإصدارات التي يمكن تثبيتها، لنقم بتثبيت الإصدار 2.5.1 المتوفر وقت كتاب هذا المقال:
</p>

<pre class="ipsCode">
$ rbenv install 2.5.1
</pre>

<p>
	من أجل تثبيت إصدار روبي الذي قمنا بتثبيته كإصدار الافتراضي استخدم الرمز <code>global</code> كجزء من الأمر:
</p>

<pre class="ipsCode">
$ rbenv global 2.5.1
</pre>

<p>
	للتحقق من أن التثبيت تم بشكل صحيح تحقق من رقم اصدار روبي:
</p>

<pre class="ipsCode">
$ ruby -v
</pre>

<p>
	إذا قمت بتثبيت نفس الاصدار السابق لابد ان تظهر لك المخرجات التالية:
</p>

<pre class="ipsCode">
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
</pre>

<p>
	لتثبيت إصدار مختلف من روبي قم تنفيذ الأمر <code>rbenv</code> مع رقم إصدار مختلف مثل: <code>rbenv install 2.3.0</code> ثم <code>rbenv global 2.3.0</code>.
</p>

<p>
	الآن لديك إصدار واحد على الأقل من روبي قم بتثبيته و تعينه باصدار افتراضي لروبي فبعد ذلك سوف نبدأ بإعداد ريلز والجواهر gems الخاصة بها.
</p>

<h2>
	الخطوة الثالثة: العمل مع الجواهر <strong>Gems</strong>
</h2>

<p>
	الجواهر Gems هي الطريقة التي يتم بها توزيع مكتبات روبي، استخدام الأمر <code>gem</code> لإدارة هذه gems كما سوف نستخدم هذا الأمر لتثبيت ريلز.
</p>

<p>
	أثناء تثبيت gem تعمل عملية التثبيت بإنشاء وثائق محلية مما يضيف وقت أطول أثناء عملية تثبيت كل gem، لذلك سنوقف هذه العملية عن طريق إنشاء ملف يسمى <code>gemrc./~</code> الذي يحتوي على الاعدادت اللازمة لإيقاف هذه الميزة:
</p>

<pre class="ipsCode">
$ echo "gem: --no-document" &gt; ~/.gemrc
</pre>

<p>
	المُحزِّم <strong>Bundler</strong> هي عبارة عن أداة يستخدمها gem لإدارة ما يعتمد عليه المشاريع، بالأمر التالي سنثبت Bundler الذي يعتمد عليه ريلز.
</p>

<pre class="ipsCode">
$ gem install bundler
</pre>

<p>
	ستظهر المخرجات التالية:
</p>

<pre class="ipsCode">
Fetching: bundler-1.16.2.gem (100%)
Successfully installed bundler-1.16.2
1 gem installed
</pre>

<p>
	يمكنك استخدام الأمر <code>gem env</code> (كلمة env بالأمر هي اختصار من كلمة environment) لمعرفة المزيد حول من البيئات والإعدادات ب gems، بإمكانك معرفة مكان تثبيت gems باستخدام متغير home انظر للمثال :
</p>

<pre class="ipsCode">
$ gem env home
</pre>

<p>
	سوف يعرض لك الناتج التالي:
</p>

<pre class="ipsCode">
/home/sammy/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0
</pre>

<p>
	بمجرد الإنتهاء من إعدادات gems يمكنك تثبيت ريلز بالخطة التالية:
</p>

<h2>
	الخطوة الرابعة: تثبيت ريلز
</h2>

<p>
	من أجل تثبيت ريلز استخدم الأمر <code>gem install</code> مع الراية <code>‎-v</code> لتحديد الإصدار، في هذا المقال التعليمي، سنثبت الإصدار 5.2.0:
</p>

<pre class="ipsCode">
$ gem install rails -v 5.2.0
</pre>

<p>
	يقوم الأمر <code>gem</code> بتثبيت الجواهر المحددة وكذلك كل ما تعتمد عليه. تُعد ريلز لتطوير الويب معقدة إذ تعتمد على العديد التبعيات ، لذلك تستغرق عملية التثبيت بعض الوقت،و لكن بالنهاية سترى رسالة تفيد بأن ريلز مثبت، بالإضافة إلى كل ما تعتمد عليه:
</p>

<pre class="ipsCode">
Successfully installed rails-5.2.0
38 gems installed
</pre>

<p>
	<strong>ملاحظة</strong>: إذا كنت ترغب في تثبيت إصدار مختلف من ريلز، يمكنك عرض الإصدارات الصالحة من ريلز من خلال إجراء عملية بحث، مما يؤدي إلى لإظهار قائمة طويلة من الإصدارات، يمكننا بعد ذلك تثبيت إصدار معين، مثل 4.2.7:
</p>

<pre class="ipsCode">
$ gem search '^rails$' --all
$ gem install rails -v 4.2.7
</pre>

<p>
	في حال كنت ترغب في تثبيت أحدث إصدار من ريلز نفذ الأمر دون تحديد رقم الاصدار:
</p>

<pre class="ipsCode">
$ gem install rails
</pre>

<p>
	يعمل rbenv عن طريق إنشاء مجلد shims، والذي يشير إلى الملفات المستخدمة بإصدار ريلز المفعل حاليًا،من خلال الأمر الفرعي <code>rehash</code> يقوم rbenv بإصلاح shims في هذا المجد لربط كل أمر في روبي عبر كل إصدار مثبت من روبي على الخادم الخاص بك. كلما تم تثبيت إصدار جديد من روبي أو gem نفذ هذا الامر.
</p>

<pre class="ipsCode">
$ rbenv rehash
</pre>

<p>
	تحقق من تثبيت ريلز بشكل صحيح عن طريق طباعة اصداره باستخدام هذا الأمر:
</p>

<pre class="ipsCode">
$ rails -v
</pre>

<p>
	إذا تم تثبيته بشكل صحيح ، سترى إصدار ريلز الذي تم تثبيته:
</p>

<pre class="ipsCode">
Rails 5.2.0
</pre>

<p>
	في هذه المرحلة سنقوم بالبدء في اختبار تثبيت ريلز والبدء في تطوير تطبيقات الويب، حافظ على تحديث rbenv باستمرار.
</p>

<h2>
	الخطوة الخامسة: تحديث rbenv
</h2>

<p>
	نظرًا لأنك قمت بتثبيت rbenv يدويًا باستخدام Git، يمكنك تحديثه إلى الإصدار الأحدث في أي وقت باستخدام أمر <code>git pull</code> في المجلد <code>rbenv./~</code>:
</p>

<pre class="ipsCode">
$ cd ~/.rbenv
$ git pull
</pre>

<p>
	هكذا سنضمن أننا نستخدم أحدث إصدار من rbenv المتاحة.
</p>

<h2>
	الخطوة السادسة: إلغاء تثبيت إصدارات روبي
</h2>

<p>
	أثناء تنزيل إصدارات إضافية من روبي يمكنك تجميع إصدارات أكثر مما تريد في المجلد <code>rbenv/versions./~</code> استخدم الأمر <code>uninstall</code> الموجود ب <code>ruby-build</code> لإزالة أي من الإصدارات السابقة على سبيل المثال إزالة الاصدار 2.1.3:
</p>

<pre class="ipsCode" id="ips_uid_179_12">
$ rbenv uninstall 2.1.3
</pre>

<p>
	باستخدام الأمر `rbenv uninstall` يمكنك من إزالة  الإصدارات القديمة من روبي بحيث لا يكون لديك تثبيت أكثر مما تستخدمه حاليًا.
</p>

<h2>
	الخطوة السابعة: إلغاء تثبيت rbenv
</h2>

<p>
	إذا قررت أنك لم تعد ترغب في استخدام rbenv، فيمكنك إزالته من نظامك ،من أجل القيام بذلك  افتح أولاً ملف `bashrc./~` في المحرر الخاص بك:
</p>

<pre class="ipsCode" id="ips_uid_179_14">
$ nano ~/.bashrc

</pre>

<p>
	ابحث عن السطرين التاليين من الملف ‎~/.bashrc ثم قم بحذفها:
</p>

<pre class="ipsCode" id="ips_uid_179_6">
export PATH="$HOME/.rbenv/bin:$PATH" eval "$(rbenv init -)"

</pre>

<p>
	احفظ الملف واخرج من المحرر،ثم قم بإزالة rbenv وجميع إصدارات روبي المثبتة بهذا الأمر:
</p>

<pre class="ipsCode" id="ips_uid_179_9">
rm -rf rbenv root</pre>

<p>
	سجل الخروج وقم بالعودة لحفظ التغييرات على الصدفة shell الخاص بك.
</p>

<h2>
	الخلاصة
</h2>

<p>
	في هذا المقال التعليمي قمت بتثبيت rbenv وريلز ويمكن الآن الانتقال إلى <a href="https://wiki.hsoub.com/Rails" rel="external">توثيق ريلز</a> على موسوعة حسوب لمزيد من المعلومات.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-ruby-on-rails-with-rbenv-on-ubuntu-18-04" rel="external nofollow">How To Install Ruby on Rails with rbenv on Ubuntu 18.04</a> لصاحبيه Brian Hogan و Lisa Tagliaferri
</p>
]]></description><guid isPermaLink="false">843</guid><pubDate>Wed, 04 Mar 2020 13:14:16 +0000</pubDate></item><item><title>Active Record Associations: &#x645;&#x631;&#x62C;&#x639; &#x627;&#x631;&#x62A;&#x628;&#x627;&#x637; has_one</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-associations-%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-has_one-r631/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_03/04-3.png.d0a829c72b0705e92bd0c4394585dd13.png" /></p>

<p>
	<a id="42___has_one_0" rel=""></a>تابعنا في<a href="https://academy.hsoub.com/programming/ruby/rails/active-record-associations-%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D8%A7%D9%84%D9%85%D9%81%D8%B5%D9%91%D9%84-r625/" rel=""> الدرس السابق</a> من هذه السلسلة مرجع الارتباط المفصّل وسنتابع في هذا الدرس الحديث عن مرجع ارتباط has_one.
</p>

<h2>
	4.2 مرجع ارتباط has_one
</h2>

<p>
	يُنشئ ارتباط <code>has_one</code> تطابق واحد لواحد (one-to-one) مع كائن آخر، بمصطلحات قاعدة البيانات، هذا الارتباط يعلن أن الصنف الآخر يحتوي على مفتاح خارجي، وإذا كان هذا الصنف يحتوي على مفتاح خارجي، فيجب عليك في هذه الحالة استخدام <code>belongs_to</code> بدلا من ذلك.
</p>

<h3>
	<a id="421____has_one_2" rel=""></a>4.2.1 الأساليب المضافة بواسطة has_one
</h3>

<p>
	عند إعلان ارتباط <code>has_one</code>، فإن الفئة المُعلنة ستحصل على 5 أساليب متعلقة بالارتباط:
</p>

<ul>
<li>
		<code>association</code>
	</li>
	<li>
		<code>(association=(associate</code>
	</li>
	<li>
		<code>({} = build_association(attributes </code>
	</li>
	<li>
		<code>({} = create_association(attributes</code>
	</li>
	<li>
		<code>({} = create_association!(attributes</code>
	</li>
	<li>
		<code>reload_association</code>
	</li>
</ul>
<p>
	في كل هذه الأساليب، يُستبدل الارتباط مع symbol المُمرر كمعامل أول إلى <code>has_one</code>، على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account
</span><span class="kwd">end</span></pre>

<p>
	فإن كل مثيل من نموذج <code>Supplier</code> سيحصل على هذه الأساليب:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_9" style="">
<span class="pln">account
account</span><span class="pun">=</span><span class="pln">
build_account
create_account
create_account</span><span class="pun">!</span><span class="pln">
reload_account</span></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			يجب عليك عند إنشاء ارتباط <code>has_one</code> أو <code>belongs_to</code> جديد استخدام بادئة <code>_build </code>لبناء الارتباط، بدلا من أسلوب <code>association.build</code> الذي سيستخدم لارتباطات <code>has_many</code> أو <code>has_and_belongs_to_many</code>، ولإنشاء واحد استخدم بادئة <code>_create</code> .
		</p>
	</div>
</blockquote>

<h3>
	<a id="4211_association_28" rel=""></a>4.2.1.1 association
</h3>

<p>
	يُرجع أسلوب association الكائن المرتبط إن وجد، وإلا، فسيرجع <code>nil</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_11" style="">
<span class="lit">@account</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">@supplier</span><span class="pun">.</span><span class="pln">account</span></pre>

<p>
	إذا أُسترد الكائن المرتبط بالفعل من قاعدة البيانات لهذا الكائن، ستٌسترجع النسخة المخبأة، ولتجاوز هذا السلوك(وإجبار قاعدة البيانات على القراءة)، استدعي <code>#reload_association</code> في الكائن الأب.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_13" style="">
<span class="lit">@account</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">@supplier</span><span class="pun">.</span><span class="pln">reload_account</span></pre>

<h3>
	<a id="4212_associationassociate_37" rel=""></a>4.2.1.2 (association=(associate
</h3>

<p>
	يُعيّن أسلوب <code>=association</code> كائن مرتبط إلى هذا الكائن، وفي ما وراء الكواليس، هذا يعني استخراج المفتاح الرئيسي من هذا الكائن وتعيين مفتاح الخارجي للكائن المرتبطة إلى نفس القيمة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_15" style="">
<span class="lit">@supplier</span><span class="pun">.</span><span class="pln">account </span><span class="pun">=</span><span class="pln"> </span><span class="lit">@account</span></pre>

<h3>
	<a id="4213_build_associationattributes___42" rel=""></a>4.2.1.3 ({} = build_association(attributes
</h3>

<p>
	يرجع أسلوب <code>build_association</code> كائن جديد للنوع المرتبط، وهذا الكائن سيُنشئ من السمات المُمررة، وسيُعين الارتباط بمفتاحه الخارجي، لكن لن يُحفظ الكائن المرتبط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_17" style="">
<span class="lit">@account</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">@supplier</span><span class="pun">.</span><span class="pln">build_account</span><span class="pun">(</span><span class="pln">terms</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Net 30"</span><span class="pun">)</span></pre>

<h3>
	<a id="4214_create_associationattributes___47" rel=""></a>4.2.1.4 ({} = create_association(attributes
</h3>

<p>
	يرجع أسلوب <code>create_association</code> كائن جديد من النوع المرتبط، وهذا الكائن سيُنشئ من السمات الممررة، وسيُعين الارتباط بمفتاحه الخارجي، وبمجرد النجاح في جميع التحقيقات (validations) المحددة في النموذج المرتبط، سيُحفظ الكائن المرتبط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_19" style="">
<span class="lit">@account</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">@supplier</span><span class="pun">.</span><span class="pln">create_account</span><span class="pun">(</span><span class="pln">terms</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Net 30"</span><span class="pun">)</span></pre>

<h3>
	<a id="4215_create_associationattributes___52" rel=""></a>4.2.1.5 ({} = create_association!(attributes
</h3>

<p>
	يعمل كما <code>create_association</code> في الأعلى، لكنه يصدر ActiveRecord::RecordInvalid إذا كان السجل (record) غير صالح.
</p>

<h3>
	<a id="422__has_one_54" rel=""></a>4-2-2 خيارات has_one
</h3>

<p>
	في حين يستخدم Rails الافتراضات الذكية والتي تعمل بشكل جيد في أغلب الأحيان، لكن في بعض الأوقات ستحتاج إلى تخصيص سلوك مرجع ارتباط <code>has_one</code>، ويمكن تحقيق هذه التخصيصات بسهولة عن طريق تمرير الخيارات عند إنشاء الارتباط، فعلى سبيل المثال، يستخدم هذا الارتباط اثنين من هذه الخيارات:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_21" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account</span><span class="pun">,</span><span class="pln"> class_name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Billing"</span><span class="pun">,</span><span class="pln"> dependent</span><span class="pun">:</span><span class="pln"> </span><span class="pun">:</span><span class="pln">nullify
</span><span class="kwd">end</span></pre>

<p>
	يدعم ارتباط has_one هذه الخيارات:
</p>

<ul>
<li>
		as:
	</li>
	<li>
		autosave:
	</li>
	<li>
		class_name:
	</li>
	<li>
		dependent:
	</li>
	<li>
		foreign_key:
	</li>
	<li>
		inverse_of:
	</li>
	<li>
		primary_key:
	</li>
	<li>
		source:
	</li>
	<li>
		source_type:
	</li>
	<li>
		through:
	</li>
	<li>
		validate:
	</li>
</ul>
<h3>
	<a id="4221_as_73" rel=""></a>4.2.2.1 as:
</h3>

<p>
	يشير تعيين خيار <code>as:</code> على أن الارتباط متعدد الأشكال، وستجد المزيد من التفاصيل حول الارتباطات متعددة الأشكال بالتفاصيل في الأعلى.
</p>

<h3>
	<a id="4222_autosave_75" rel=""></a>4.2.2.2 autosave:
</h3>

<p>
	إذا عيّنت خيار <code>autosave:</code> إلى <code>true</code>، فإن Rails سيحفظ أي أعضاء محملين وسيدمر الأعضاء الذي وُضع عليهما علامة للتدمير كلما حفظت كائن الأب.
</p>

<h3>
	<a id="4223_class_name_77" rel=""></a>4.2.2.3 class_name:
</h3>

<p>
	إذا لم يكن بالإمكان اشتقاق اسم النموذج الآخر من اسم الارتباط، يمكنك استخدام خيار <code>class_name:</code> لتوفير اسم النموذج، فعلى سبيل المثال، إذا كان المُورّد يمتلك حساب، لكن اسم النموذج الحالي الذي يحتوي على الحسابات هو Billing، فيمكنك فعل التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_23" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account</span><span class="pun">,</span><span class="pln"> class_name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Billing"</span><span class="pln">
</span><span class="kwd">end</span></pre>

<h3>
	<a id="4224_dependent_84" rel=""></a>4.2.2.4 dependent:
</h3>

<p>
	يتحكم في ما يحدث للكائن المرتبط عند حذف مالكه:
</p>

<ul>
<li>
		destroy: سيدمر كائن المرتبط أيضا.
	</li>
	<li>
		delete: سيحذف الكائن المرتبط مباشرة من قاعدة البيانات (ولن يعمل دوال الاستدعاء).
	</li>
	<li>
		nullify: سيُعين المفتاح الخارجي إلى NULL ولن يعمل دوال الاستدعاء.
	</li>
	<li>
		restrict_with_exception: سيصدر استثناء إذا كان هنالك كائن مرتبط.
	</li>
	<li>
		restrict_with_error: سيضاف خطأ إلى المالك إذا كان هنالك كائن مرتبط.
	</li>
</ul>
<p>
	من الضروري عدم تعيين أو ترك خيار <code>nullify:</code> للارتباطات التي تملك قيود NOT NULL على قاعدة البيانات، إذا لم تعيّن dependent لتدمير هذه الارتباطات فلن تتمكن من تغيير كائن المرتبط لأنه سيُعيّن المفتاح الخارجي للكائن المرتبط الأولي إلى NULL التي هي غير مسموح بها.
</p>

<h3>
	<a id="4225_foreign_key_93" rel=""></a>4.2.2.5 foreign_key:
</h3>

<p>
	بالاتفاق، يفترض Rails أن العمود الذي يحمل المفتاح الخارجي في النموذج الآخر هو اسم النموذج مع إضافة بادئة <code>id_</code>، ويسمح لك خيار <code>:foreign_key</code> بتعيين اسم المفتاح الخارجي مباشرة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_25" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account</span><span class="pun">,</span><span class="pln"> foreign_key</span><span class="pun">:</span><span class="pln"> </span><span class="str">"supp_id"</span><span class="pln">
</span><span class="kwd">end</span></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تنبيه:</strong><br>
			على أي حال، لن ينشئ Rails أعمدة مفتاح خارجي لك، ستحتاج إلى تعريف صريح لهم كجزء من التهجيرات.
		</p>
	</div>
</blockquote>

<h3>
	<a id="4226_inverse_of_102" rel=""></a>4.2.2.6 inverse_of:
</h3>

<p>
	يحدد خيار <code>inverse_of:</code> اسم ارتباط <code>belongs_to</code> والذي هو عكس هذا الارتباط، وهذا الخيار لا يعمل في التركيبة مع خيارات <code>through:</code> أو <code>as:</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_27" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account</span><span class="pun">,</span><span class="pln"> inverse_of</span><span class="pun">:</span><span class="pln"> </span><span class="pun">:</span><span class="pln">supplier
</span><span class="kwd">end</span><span class="pln">
 
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Account</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  belongs_to </span><span class="pun">:</span><span class="pln">supplier</span><span class="pun">,</span><span class="pln"> inverse_of</span><span class="pun">:</span><span class="pln"> </span><span class="pun">:</span><span class="pln">account
</span><span class="kwd">end</span></pre>

<h3>
	<a id="4227_primary_key_113" rel=""></a>4.2.2.7 primary_key:
</h3>

<p>
	يفترض Rails أن العمود الذي يحمل المفتاح الرئيسي في هذا النموذج هو <code>id</code>، يمكنك تجاوز ذلك وتصريح المفتاح الرئيسي عن طريق خيار <code>primary_key:</code>
</p>

<h3>
	<a id="4228_source_115" rel=""></a>4.2.2.8 source:
</h3>

<p>
	يحدد خيار <code>source:</code> اسم ارتباط المصدر لارتباط <code>has_one :through</code>.
</p>

<h3>
	<a id="4229_source_type_117" rel=""></a>4.2.2.9 source_type:
</h3>

<p>
	يحدد خيار <code>source_type:</code> ارتباط المصدر لارتباط <code>has_one :through</code> الذي يمر عبر ارتباط متعدد الأشكال.
</p>

<h3>
	<a id="42210_through_119" rel=""></a>4.2.2.10 through:
</h3>

<p>
	يحدد خيار <code>through:</code> نموذج الضم والذي يتم من خلاله تنفيذ الاستعلام، تم الحديث حول <code>has_one :through</code> في وقت سابق من هذا الدليل.
</p>

<h3>
	<a id="42211_validate_121" rel=""></a>4.2.2.11 validate:
</h3>

<p>
	إذا عُيّن خيار <code>validate:</code> إلى <code>true</code>، فسيتحقق من الكائنات المرتبطة كلما حفظت هذا الكائن، افتراضيا، قيمة هذا الخيار هي <code>false</code>، ولن يتحقق مع كائنات المرتبطة عند حفظ هذا الكائن.
</p>

<h3>
	<a id="423__Scopes__belongs_to_123" rel=""></a>4.2.3 نطاقات Scopes لـ belongs_to
</h3>

<p>
	في بعض الأحيان قد تحتاج إلى تخصيص الاستعلام المُستخدم من قبل <code>has_one</code>، ويمكن تحقيق هذه التخصيصات عن طريق كتلة <code>scope</code>، فعلى سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_29" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> where active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	يمكنك استخدام أي من أساليب الاستعلامات القياسية داخل كتلة <code>scope</code>، وستجد تفاصيلها في الأسفل:
</p>

<ul>
<li>
		<code>where</code>
	</li>
	<li>
		<code>includes</code>
	</li>
	<li>
		<code>readonly</code>
	</li>
	<li>
		<code>select</code>
	</li>
</ul>
<h3>
	<a id="4231_where_135" rel=""></a>4.2.3.1 where
</h3>

<p>
	يسمح لك أسلوب <code>where</code> بتحديد شروط الكائن المرتبط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_31" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> where </span><span class="str">"confirmed = 1"</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">end</span></pre>

<h3>
	<a id="4232_includes_142" rel=""></a>4.2.3.2 includes
</h3>

<p>
	يمكنك استخدام أسلوب <code>includes</code> لتحديد الارتباطات من الدرجة الثانية التي تريد تحميلها (<code>eager-loaded</code>) عند استخدام هذا الارتباط، فعلى سبيل المثال، فكر في هذه النماذج:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_33" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account
</span><span class="kwd">end</span><span class="pln">
 
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Account</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  belongs_to </span><span class="pun">:</span><span class="pln">supplier
  belongs_to </span><span class="pun">:</span><span class="pln">representative
</span><span class="kwd">end</span><span class="pln">
 
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Representative</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_many </span><span class="pun">:</span><span class="pln">accounts
</span><span class="kwd">end</span></pre>

<p>
	إذا كنت تسترد الممثلين مباشرة من المُوردين بشكل كثير (<code>supplier.account.representative@</code>)، فيمكنك جعل شيفرتك البرمجية أكثر كفاءة من خلال تضمين الممثلين إلى الارتباط من المُوردين إلى الحسابات:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_35" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Supplier</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_one </span><span class="pun">:</span><span class="pln">account</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> includes </span><span class="pun">:</span><span class="pln">representative </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">
 
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Account</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  belongs_to </span><span class="pun">:</span><span class="pln">supplier
  belongs_to </span><span class="pun">:</span><span class="pln">representative
</span><span class="kwd">end</span><span class="pln">
 
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Representative</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  has_many </span><span class="pun">:</span><span class="pln">accounts
</span><span class="kwd">end</span></pre>

<h3>
	<a id="4233_readonly_173" rel=""></a>4.2.3.3 readonly
</h3>

<p>
	سيكون الكائن المرتبط للقراءة فقط عند استرداده عن طريق الارتباط إذا استخدمت <code>readonly</code>.
</p>

<h3>
	<a id="4234_select_175" rel=""></a>4.2.3.4 select
</h3>

<p>
	يسمح لك أسلوب <code>select</code> بتجاوز جملة <code>SELECT</code> (في SQL) والتي تُستخدم لاسترداد البيانات حول الكائن المرتبط، وبشكل افتراضي، سيسترد Rails جميع الأعمدة.
</p>

<h3>
	<a id="424______177" rel=""></a>4.2.4 هل توجد أية كائنات مرتبطة؟
</h3>

<p>
	يمكنك معرفة هل توجد أية كائنات مرتبطة عن طريقة استخدام أسلوب <code>?association.nil</code>
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6835_37" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="lit">@supplier</span><span class="pun">.</span><span class="pln">account</span><span class="pun">.</span><span class="kwd">nil</span><span class="pun">?</span><span class="pln">
  </span><span class="lit">@msg</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"No account found for this supplier"</span><span class="pln">
</span><span class="kwd">end</span></pre>

<h3>
	<a id="425____185" rel=""></a>4.2.5 متى تحفظ الكائنات؟
</h3>

<p>
	عند تعيين كائن إلى ارتباط <code>has_one</code>، سيُحفظ ذلك الكائن بشكل تلقائي (من أجل تحديث مفتاحه الخارجي)، بالإضافة إلى ذلك، يُحفظ أي كائن أُستبدل بشكل تلقائي لأن المفتاح الخارجي سيتغير أيضا.<br>
	إذا فشلت عملية الحفظ بسبب أخطاء تحقق (validation)، فإن إعلان التعيين سيرجع <code>false</code> ويُلغى التعيين نفسه.<br>
	إذا لم يُحفظ (سترجع <code>?new_record</code> قيمة <code>false</code>) الكائن الأب (الذي يعلن ارتباط<code>has_one</code> )، فإن الكائنات الأبناء لن يُحفظوا أيضا، وسيُحفظون تلقائيا عند حفظ الكائن الأب.<br>
	إذا أردت تعيين كائن إلى ارتباط <code>has_one</code> بدون حفظ الكائن، استخدم أسلوب <code>association.build</code>.
</p>

<p>
	وسنتابع في الدرس القادم شرح مرجع ارتباط has_many (الأساليب المضافة والخيارات).
</p>

<p>
	 
</p>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/association_basics.html" rel="external nofollow">Ruby on Rails</a>
</p>
]]></description><guid isPermaLink="false">631</guid><pubDate>Sat, 03 Mar 2018 14:43:36 +0000</pubDate></item><item><title>Active Record Associations: &#x645;&#x631;&#x62C;&#x639; &#x627;&#x644;&#x627;&#x631;&#x62A;&#x628;&#x627;&#x637; &#x627;&#x644;&#x645;&#x641;&#x635;&#x651;&#x644;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-associations-%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D8%A7%D9%84%D9%85%D9%81%D8%B5%D9%91%D9%84-r625/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_02/5a8fdbfb96306_25(1).png.96115c3005f5f4cd7c301d75ca31c8ed.png" /></p>

<p>
	تعرفنا في <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-associations-%D9%86%D8%B5%D8%A7%D8%A6%D8%AD%D8%8C-%D8%AE%D8%AF%D8%B9-%D9%88%D8%AA%D8%AD%D8%B0%D9%8A%D8%B1%D8%A7%D8%AA-r621/" rel="">الدرس السابق</a> على أهم الخدع، النصائح والتحذيرات وسنتابع في هذا الدرس مرجع الارتباط المفصّل.
</p>

<h2 id="مرجع-الارتباط-المفصّل">
	4 مرجع الارتباط المفصّل
</h2>

<p>
	ستجد في الأقسام التالية تفاصيل حول كل نوع من أنواع الارتباط، بما في ذلك الأساليب التي تضيفها والخيارات التي يمكنك استخدامها عند إعلان الارتباط.
</p>

<h3 id="مرجع-ارتباط-belongs_to">
	4.1 مرجع ارتباط belongs_to
</h3>

<p>
	ينشئ ارتباط <code>belongs_to</code> تطابق واحد لواحد (one-to-one) مع نموذج آخر، بمصطلحات قاعد البيانات، يعني هذا الارتباط أن هذا الصنف يحتوي على مفتاح خارجي، إذا كان الصنف الآخر يحتوي على مفتاح خارجي، فيجب عليك في هذه الحالة استخدام <code>has_one</code> بدلًا من ذلك.
</p>

<h3 id="أساليب-مضافة-بواسطة-belongs_to">
	4.1.1 أساليب مضافة بواسطة belongs_to
</h3>

<p>
	عند إعلان ارتباط <code>belongs_to</code>، فسيحصل الصنف المعلن على 5 أساليب مرتبطة بالارتباط:
</p>

<ul>
<li>
		<code>association</code>
	</li>
	<li>
		<code>association=(associate)</code>
	</li>
	<li>
		<code>({} = build_association(attributes</code>
	</li>
	<li>
		<code>({} = create_association(attributes</code>
	</li>
	<li>
		<code>({} = create_association!(attributes</code>
	</li>
	<li>
		<code>reload_association</code>
	</li>
</ul>
<p>
	في جميع هذه النماذج، سيُستبدل الارتباط مع <code>symbol</code> الذي مُرر كمعامل أول إلى <code>belongs_to</code>، فعلى سبيل المثال، هذا الإعلان:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Book</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  belongs_to </span><span class="pun">:</span><span class="pln">author
</span><span class="kwd">end</span></pre>

<p>
	سيحصل كل مثيل نموذج <code>Book</code> على هذه الأساليب:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_9" style="">
<span class="pln">author
author</span><span class="pun">=</span><span class="pln">
build_author
create_author
create_author</span><span class="pun">!</span><span class="pln">
reload_author</span></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			يجب عليك استخدم بادئة <code>_build</code> عند تهيئة ارتباط <code>has_one</code> أو <code>belongs_to</code> لبناء الارتباط، بدلًا من أسلوب <code>association.build</code> الذي يستخدم لارتباطات <code>has_many</code> أو <code>has_and_belongs_to_many</code>، ولإنشاء واحد، استخدم بادئة <code>_create</code>.
		</p>
	</div>
</blockquote>

<h3 id="association">
	4.1.1.1 association
</h3>

<p>
	يرجع أسلوب <code>association</code> الكائن المقترن إذا وجد، وإلا فسيُرجع <code>nil</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_11" style="">
<span class="lit">@author</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">@book</span><span class="pun">.</span><span class="pln">author</span></pre>

<p>
	إذا أُسترد الكائن من قاعدة البيانات لهذا الكائن، ستُرجع النسخة المخبئة، ولتجاوز هذا السلوك (وإجبار القراءة من قاعدة البيانات)، استدعي <code>reload_association#</code> في كائن الأب.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>@author = @book.reload_author
</code></pre>

<h4 id="associationassociate">
	4.1.1.2 (association=(associate
</h4>

<p>
	يعيّن أسلوب <code>association=</code> كائن مرتبط لهذا الكائن، في ما وراء الكواليس، يعني هذا استخراج المفتاح الأساسي من الكائن المرتبط وتعيين قيمة المفتاح الخارجي للكائن لنفس قيمته.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>@book.author = @author
</code></pre>

<h3 id="build_associationattributes--">
	4.1.1.3 ({} = build_association(attributes 
</h3>

<p>
	يُرجع أسلوب <code>build_association</code> كائن جديد لنوع المرتبط، هذا الكائن سيُنشئ من السمات المُمرّرة وسيُعين الارتباط من خلال المفتاح الخارجي لكن لن بعد يحفظ بعد الكائن المرتبط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>@author = @book.build_author(author_number: 123,
                                  author_name: "John Doe")
</code></pre>

<h3 id="create_associationattributes--">
	4.1.1.4 ({} = create_association(attributes
</h3>

<p>
	سيرجع أسلوب <code>create_association</code> كائن جديد لنوع المرتبط، هذا الكائن سيُنشئ من السمات المُمررة وسيُعين الارتباط من خلال المفتاح الخارجي، وبمجرد تمرير جميع عمليات التحقيق validations المحددة على النموذج المرتبط، سيُحفظ الكائن المرتبط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>@author = @book.create_author(author_number: 123,
                                   author_name: "John Doe")
</code></pre>

<h3 id="create_associationattributes---1">
	4.1.1.5 ({} = create_association!(attributes
</h3>

<p>
	يعمل كما <code>create_association</code> في الأعلى، لكنه يُصدر ActiveRecord::RecordInvalid إذا كان السجل record غير صالح.
</p>

<h3 id="خيارات-لـ-belongs_to">
	4.1.2 خيارات لـ belongs_to
</h3>

<p>
	في حين يستخدم Rails افتراضات ذكية ستعمل بشكل صحيح في أغلب الأحيان، ستحتاج في بعض الأحيان إلى تخصيص مرجع سلوك ارتباط <code>belongs_to</code>، ويمكن تحقيق هذه التخصيصات بسهولة عن طريق تمرير الخيارات وكتل النطاق (scope) عند إنشاء الارتباط، فعلى سبيل المثال، هذا الارتباط يستخدم هذين الخيارين:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author, dependent: :destroy,
    counter_cache: true
end
</code></pre>

<p>
	يدعم ارتباط <code>belongs_to</code> هذه الخيارات:
</p>

<ul>
<li>
		<code>autosave:</code>
	</li>
	<li>
		<code>class_name:</code>
	</li>
	<li>
		<code>counter_cache:</code>
	</li>
	<li>
		<code>dependent:</code>
	</li>
	<li>
		<code>foreign_key:</code>
	</li>
	<li>
		<code>primary_key:</code>
	</li>
	<li>
		<code>inverse_of:</code>
	</li>
	<li>
		<code>polymorphic:</code>
	</li>
	<li>
		<code>touch:</code>
	</li>
	<li>
		<code>validate:</code>
	</li>
	<li>
		<code>optional:</code>
	</li>
</ul>
<h3 id="autosave">
	4.1.2.1 autosave:
</h3>

<p>
	إذا عيّنت خيار <code>autosave:</code> إلى <code>true</code>، فسيحفظ Rails جميع أعضاء المحمّلين وسيدمر الأعضاء الذين وضع عليهم علامة التدمير كلما حفظت كائن الأب.
</p>

<h3 id="class_name">
	4.1.2.2 class_name:
</h3>

<p>
	إذا لم يكن بالإمكان اشتقاق اسم النموذج الآخر من اسم الارتباط، يمكنك استخدام خيار <code>class_name:</code> لتوفير اسم النموذج، فعلى سبيل المثال، إذا كان الكتاب ينتمي إلى المؤلف، لكن اسم فعلي للنموذج الذي يحتوي على المؤلفين هو <code>Patron</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author, class_name: "Patron"
end
</code></pre>

<h3 id="counter_cache">
	4.1.2.3 counter_cache:
</h3>

<p>
	يمكنك استخدام خيار <code>counter_cache:</code> لتجعل عملية العثور على عدد الكائنات التابعة أكثر كفاءة، على سبيل المثال هذه النماذج:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author
end
class Author &lt; ApplicationRecord
  has_many :books
end
</code></pre>

<p>
	مع هذه الإعلانات، يتطلب طلب قيمة <code>author.books.size@</code> الاتصال بقاعدة البيانات لتنفيذ استعلام <code>(*)COUNT</code>، ولنتجنب هذا الاتصال، يمكنك إضافة ذاكرة مؤقتة لتخزين العدد إلى نموذج الانتماء:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author, counter_cache: true
end
class Author &lt; ApplicationRecord
  has_many :books
end
</code></pre>

<p>
	مع هذا الإعلان، سيُبقي Rails قيمة الذاكرة المؤقتة مُحدّثة، وسيجيب بتلك القيمة عند الطلب من أسلوب <code>size</code>.<br>
	على الرغم من تحديد خيار <code>counter_cache:</code> في النموذج الذي يتضمن إعلان <code>belongs_to</code>، يجب إضافة العمود الحالي إلى النموذج المرتبط (<code>has_many</code>)، في الحالة أعلاه، ستحتاج إلى إضافة عمود باسم <code>books_count</code> إلى نموذج <code>Author</code>.<br>
	يمكنك تجاوز اسم الافتراضي للعمود من خلال تحديد اسم العمود المخصص في إعلان <code>counter_cache</code> بدلا من <code>true</code>، فعلى سبيل المثال، لاستخدام <code>count_of_books</code> بدلا من <code>books_count</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author, counter_cache: :count_of_books
end
class Author &lt; ApplicationRecord
  has_many :books
end
</code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			تحتاج إلى تحديد خيار <code>counter_cache:</code> في جانب <code>belongs_to</code> من الارتباط.<br>
			تضاف أعمدة ذاكرة التخزين المؤقت إلى قائمة النموذج التي تحتوي على سمات القراءة فقط من خلال <code>attr_readonly</code>.
		</p>
	</div>
</blockquote>

<h3 id="dependent">
	4.1.2.4 :dependent
</h3>

<p>
	إذا قمت بتعيين خيار <code>dependent:</code> إلى:
</p>

<ul>
<li>
		<code>destroy:</code>، عند تدمير الكائن، ستُستدعى <code>destroy</code> على الكائنات المرتبطة.
	</li>
	<li>
		<code>delete:</code>، عند تدمير الكائن، ستُحذف جميع الكائنات المرتبطة بها مباشرة من قاعدة البيانات دون استدعاء أسلوب <code>destroy</code>.
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تنبيه:</strong><br>
			يجب عليك عدم تحديد هذا الخيار على ارتباط <code>belongs_to</code> المتصل مع ارتباط <code>has_many</code> على الصنف الآخر، لأنه قد يؤدي هذا إلى سجلات يتيمة في قاعدة البيانات.
		</p>
	</div>
</blockquote>

<h3 id="foreign_key">
	4.1.2.5 foreign_key:
</h3>

<p>
	بالاتفاق، يفترض Rails أن العمود المستخدم لحمل المفتاح الخارجي في هذا النموذج هو اسم الارتباط مع إضافة بادئة <code>id_</code>، خيار <code>foreign_key:</code> يُتيح لك تعيين اسم المفتاح الخارجي مباشرة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author, class_name: "Patron",
                        foreign_key: "patron_id"
end
</code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			في أي حال، لن ينشئ Rails عمود المفتاح الخارجي لك، ستحتاج إلى تعريفهم بشكل صريح كجزء من عمليات التهجير.
		</p>
	</div>
</blockquote>

<h3 id="primary_key">
	4.1.2.6 primary_key:
</h3>

<p>
	بالاتفاق، يفترض Rails أن عمود <code>id</code> يُستخدم لاحتواء المفتاح الرئيسي للجداول، ويسمح لك خيار <code>primary_key:</code> بتحديد عمود مختلف.<br>
	على سبيل المثال، إذا كان لدينا جدول <code>users</code> مع <code>guid</code> كمفتاح رئيسي، أردنا جدول <code>todos</code> منفصل لاحتواء المفتاح الخارجي <code>user_id</code> في عمود <code>guid</code>، ثم يمكننا استخدام <code>primary_key</code> لتحقيق ما يشابه هذا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class User &lt; ApplicationRecord
  self.primary_key = 'guid' # primary key is guid and not id
end
 
class Todo &lt; ApplicationRecord
  belongs_to :user, primary_key: 'guid'
end
</code></pre>

<p>
	عند تنفيذ <code>user.todos.create@</code> فستكون قيمة <code>user_id</code> في سجل <code>todo@</code> كقيمة <code>guid</code> في <code>user@</code>.
</p>

<h3 id="inverse_of">
	4.1.2.7 inverse_of:
</h3>

<p>
	يحدد خيار <code>inverse_of:</code> اسم عكس هذا الارتباط وهي <code>has_many</code> أو <code>has_one</code>، وهذه لا تعمل في التركيبة مع خيارات <code>polymorphic:</code>
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Author &lt; ApplicationRecord
  has_many :books, inverse_of: :author
end
 
class Book &lt; ApplicationRecord
  belongs_to :author, inverse_of: :books
end
</code></pre>

<h3 id="polymorphic">
	4.1.2.8 polymorphic:
</h3>

<p>
	يشير تمرير <code>true</code> إلى خيار <code>polymorphic:</code> إلى أن الارتباط متعدد الأشكال، وسنتحدث عن الارتباطات متعدد الأشكال لاحقا في هذا الدليل.
</p>

<h3 id="touch">
	4.1.2.9 touch:
</h3>

<p>
	إذا عيّنت خيار <code>touch:</code> إلى <code>true</code>، فإن <code>timestamp</code> لـ <code>updated_at</code> أو <code>updated_on</code> في كائن المرتبط سيُعيّن إلى الوقت الحالي كلما حُفظ الكائن أو دُمر:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author, touch: true
end
 
class Author &lt; ApplicationRecord
  has_many :books
end
</code></pre>

<p>
	في هذه الحالة، حفظ أو تدمير كتاب سيٌحدّث <code>timestamp</code> في المؤلف المرتبط به، يمكنك أيضًا تحديد سمة <code>timestamp</code> معينة للتحديث:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author, touch: :books_updated_at
end
</code></pre>

<h3 id="validate">
	4.1.2.10 validate:
</h3>

<p>
	إذا عيّنت خيار <code>validate:</code> إلى <code>true</code>، فسيتحقق (Validate) الكائنات المرتبطة كلما حفظت هذا الكائن. وهذا الخيار يساوي <code>false</code> بشكل افتراضي، ولن يتحقق الكائنات المرتبطة عند حفظ الكائن.
</p>

<h3 id="optional">
	4.1.2.11 optional:
</h3>

<p>
	إذا عيّنت خيار <code>optional:</code> إلى <code>true</code>، فلن يتحقق من وجود الكائن المرتبط، وهذا الخيار false بشكل افتراضي.
</p>

<h3 id="نطاقات-scopes-لـ-belongs_to">
	4.1.3 نطاقات Scopes لـ belongs_to
</h3>

<p>
	في بعض الأحيان قد تحتاج إلى تخصيص الاستعلام المُستخدم من قبل <code>belongs_to</code>، ويمكن تحقيق هذه التخصيصات عن طريق كتلة <code>scope</code>، فعلى سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author, -&gt; { where active: true },
                        dependent: :destroy
end
</code></pre>

<p>
	يمكنك استخدام أي من أساليب الاستعلامات القياسية داخل كتلة <code>scope</code>، وستجد تفاصيل التالية في الأسفل:
</p>

<ul>
<li>
		<code>where</code>
	</li>
	<li>
		<code>includes</code>
	</li>
	<li>
		<code>readonly</code>
	</li>
	<li>
		<code>select</code>
	</li>
</ul>
<h3 id="where">
	4.1.3.1 where
</h3>

<p>
	يسمح لك أسلوب <code>where</code> بتحديد شروط كائن المرتبط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class book &lt; ApplicationRecord
  belongs_to :author, -&gt; { where active: true }
end
</code></pre>

<h3 id="includes">
	4.1.3.2 includes
</h3>

<p>
	يمكنك استخدام أسلوب <code>includes</code> لتحديد الارتباطات من الدرجة الثانية التي تريد تحميلها (<code>eager-loaded</code>) عند استخدام هذا الارتباط، فعلى سبيل المثال، فكر في هذه النماذج:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class LineItem &lt; ApplicationRecord
  belongs_to :book
end
 
class Book &lt; ApplicationRecord
  belongs_to :author
  has_many :line_items
end
 
class Author &lt; ApplicationRecord
  has_many :books
end
</code></pre>

<p>
	إذا كنت تسترد المؤلفين مباشرة من سطر العناصر بشكل كثير (<code>line_item.book.author@</code>)، فيمكنك جعل شيفرتك البرمجية أكثر كفاءة من خلال تضمين المؤلفين إلى الارتباط من سطر العناصر إلى الكتب:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>class LineItem &lt; ApplicationRecord
  belongs_to :book, -&gt; { includes :author }
end
 
class Book &lt; ApplicationRecord
  belongs_to :author
  has_many :line_items
end
 
class Author &lt; ApplicationRecord
  has_many :books
end
</code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			لا حاجة إلى استخدام <code>includes</code> للارتباطات الفورية، فإذا كان لديك <code>Book belongs_to :author </code>فيُحمل المؤلف (<code>eager-loaded</code>) بشكل تلقائي عند الحاجة.
		</p>
	</div>
</blockquote>

<h3 id="readonly">
	4.1.3.3 readonly
</h3>

<p>
	سيكون الكائن المرتبط قابل للقراءة فقط عند استرداده عن طريق الارتباط إذا استخدمت <code>readonly</code>.
</p>

<h3 id="select">
	4.1.3.4 select
</h3>

<p>
	يسمح لك أسلوب <code>select</code> بتجاوز جملة <code>SELECT</code> (في SQL) والتي تُستخدم لاسترداد البيانات حول الكائن المرتبط، وبشكل افتراضي، سيسترد Rails جميع الأعمدة.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			إذا استخدمت أسلوب <code>select</code> على ارتباط <code>belongs_to</code>، يجب عليك تعيين خيار <code>:foreign_key</code> لضمان صحّة النتائج.
		</p>
	</div>
</blockquote>

<h3 id="هل-توجد-أية-كائنات-مرتبطة؟">
	4.1.4 هل توجد أية كائنات مرتبطة؟
</h3>

<p>
	يمكنك معرفة هل توجد أية كائنات مرتبطة عن طريقة استخدام أسلوب <code>?association.nil</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6719_7" style="">
<code>if @book.author.nil?
  @msg = "No author found for this book"
end
</code></pre>

<h3 id="متى-تُحفظ-الكائنات؟">
	4.1.5 متى تُحفظ الكائنات؟
</h3>

<p>
	إن تعيين كائن إلى ارتباط <code>belongs_to</code> لن يحفظ الكائن بشكل تلقائي، ولن يحفظ كائن المرتبط أيضًا.
</p>

<p>
	وسنتابع في الدرس القادم من هذه السلسلة الحديث عن مرجع ارتباط has_one
</p>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/association_basics.html" rel="external nofollow">Ruby on Rails</a>
</p>
]]></description><guid isPermaLink="false">625</guid><pubDate>Sun, 25 Feb 2018 15:02:00 +0000</pubDate></item><item><title>Active Record Associations: &#x646;&#x635;&#x627;&#x626;&#x62D;&#x60C; &#x62E;&#x62F;&#x639; &#x648;&#x62A;&#x62D;&#x630;&#x64A;&#x631;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-associations-%D9%86%D8%B5%D8%A7%D8%A6%D8%AD%D8%8C-%D8%AE%D8%AF%D8%B9-%D9%88%D8%AA%D8%AD%D8%B0%D9%8A%D8%B1%D8%A7%D8%AA-r621/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_02/5a886a170ef96_18(1).png.a24c008a8e8f5706a1890578dd698886.png" /></p>

<p>
	تعرفنا في <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-associations-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-r617/" rel="">الدرس السابق</a> على الارتباطات وأنواعها وسنتابع في هذا الدرس أهم النصائح والخدع والتحذيرات.
</p>

<h2 id="نصائح،-خدع-وتحذيرات">
	3 نصائح، خدع وتحذيرات
</h2>

<p>
	يجب عليك معرفة هذه الأشياء لتستخدم ارتباطات Active Record بشكل أفضل وأكفأ في تطبيقات Rails:
</p>

<ul>
<li>
		التحكم في التخزين المؤقت.
	</li>
	<li>
		تجنب تضارب الأسماء.
	</li>
	<li>
		تحديث المخطط.
	</li>
	<li>
		التحكم في نطاق (scope) الارتباط.
	</li>
	<li>
		الارتباطات ثنائية الاتجاه.
	</li>
</ul>
<h3 id="التحكم-في-التخزين-المؤقت">
	3.1 التحكم في التخزين المؤقت
</h3>

<p>
	تبنى جميع الارتباطات حول التخزين المؤقت، والذي يحافظ على نتيجة الاستعلام الأخيرة متاحة للعمليات القادمة، يتم تقاسم ذاكرة التخزين المؤقت عبر الأساليب، على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<span class="pln">author</span><span class="pun">.</span><span class="pln">books                 </span><span class="com"># retrieves books from the database</span><span class="pln">
author</span><span class="pun">.</span><span class="pln">books</span><span class="pun">.</span><span class="pln">size            </span><span class="com"># uses the cached copy of books</span><span class="pln">
author</span><span class="pun">.</span><span class="pln">books</span><span class="pun">.</span><span class="pln">empty</span><span class="pun">?</span><span class="pln">          </span><span class="com"># uses the cached copy of books</span></pre>

<p>
	لكن ماذا لو أردنا إعادة تحميل التخزين المؤقت، لأن البيانات قد تتغير عن طريق أجزاء اخرى من التطبيق؟ فقط أدعو إعادة التحميل في الارتباط:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>author.books                 # retrieves books from the database
author.books.size            # uses the cached copy of books
author.books.reload.empty?   # discards the cached copy of books
                             # and goes back to the database
</code></pre>

<h3 id="تجنب-تضارب-الأسماء">
	3.2 تجنب تضارب الأسماء
</h3>

<p>
	أنت لا تملك حرية كاملة في اختيار الاسم الذي تريده للارتباطات، لإن إنشاء الارتباط سيضيف أسلوب بهذا الاسم إلى النموذج، ومن السيئ إعطاء اسم ارتباط مستخدم بالفعل لمثيل أسلوب <code>ActiveRecord::Base</code>، فأسلوب الارتباط سيتجاوز أسلوب الأساس وسيكسر الأشياء، من الأسماء السيئة: attributes و connection.
</p>

<h3 id="تحديث-المخطط">
	3.3 تحديث المخطط
</h3>

<p>
	الارتباطات مفيدة للغاية لكنها ليست سحرية، فأنت مسؤول عن المحافظة على مخطط قاعدة البيانات ليطابق الارتباطات، وهذا يعني شيئين في الممارسة العملية حسب نوع الارتباطات التي تصنعها، فارتباطات <code>belongs_to</code> تحتاج إلى إنشاء مفاتيح خارجية، ولارتباطات <code>has_and_belongs_to_many</code> ستحتاج إلى إنشاء جدول الضم المناسب.
</p>

<h3 id="إنشاء-مفاتيح-خارجية-لارتباطات-belongs_to">
	3.3.1 إنشاء مفاتيح خارجية لارتباطات belongs_to
</h3>

<p>
	عندما تعلن عن ارتباط <code>belongs_to</code>، ستحتاج إلى إنشاء مفاتيح خارجية حسب الحاجة، فعلى سبيل المثال، فكر في هذا النموذج:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author
end
</code></pre>

<p>
	يحتاج هذا الإعلان إلى أن يُدعم عن طريق مفتاح خارجي مناسب مُعلن في جدول books:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class CreateBooks &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :books do |t|
      t.datetime :published_at
      t.string   :book_number
      t.integer  :author_id
    end
  end
end
</code></pre>

<p>
	إذا أنشئت ارتباط بعد وقت من إنشاء النموذج الأساسي، ستحتاج إلى تذكر إنشاء تهجير <code>add_column</code> لتوفير مفتاح الخارجي الضروري.<br>
	من الممارسات الجيدة إضافة فهرس (<code>index</code>) إلى المفتاح الخارجي لتحسين أداء الطلبات وإضافة قيد على المفتاح الخارجي لضمان سلامة البيانات المرجعية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class CreateBooks &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :books do |t|
      t.datetime :published_at
      t.string   :book_number
      t.integer  :author_id
    end
 
    add_index :books, :author_id
    add_foreign_key :books, :authors
  end
end
</code></pre>

<h3 id="إنشاء-جداول-الضم-لارتباطات-has_and_belongs_to_many">
	3.3.2 إنشاء جداول الضم لارتباطات has_and_belongs_to_many
</h3>

<p>
	إذا أنشئت ارتباط <code>has_and_belongs_to_many</code>، فستحتاج إلى إنشاء جدول الضم (joining table)، إذا لم يحدد اسم جدول الضم بشكل صريح عن طريق خيار <code>join_table:</code>، فسينشئ Active Record الاسم عن طريق استخدام الكتاب المعجمي لأسماء الصنف، فالضم بين نماذج المؤلف والكتاب سيُكوّن اسم جدول الضم بشكل افتراضي هو “<code>authors_books</code>”، لأن A تأتي قبل B في الترتيب المعجمي.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تنبيه:</strong><br>
			تُحسب الأسبقية بين أسماء النماذج باستخدام العامل <code>&lt;=&gt;</code> للسلاسل النصية، وهذا يعني إذا كانت السلاسل النصية ذات أطوال مختلفة، وكانت كلا السلسلتين متساويتين مقارنة بالسلسلة الأقصر، فإن السلسلة النصية الأطول ذا أسبقية أعلى من السلسلة الأقصر، فعلى سبيل المثال، قد تملك جدول “<code>paper_boxes</code>” وجدول “<code>papers</code>” لإنشاء اسم جدول الضم “<code>papers_paper_boxes</code>” بسبب طول اسم “<code>paper_boxes</code>”، لكن في الحقيقة سيكون اسم جدول الضم هو “<code>paper_boxes_papers</code>” (لأن ‘_’ هي أقل من ‘s’ في أغلب الترميزات الشائعة).
		</p>
	</div>
</blockquote>

<p>
	مهما كان الاسم، يجب عليك إنشاء جدول الضم يدويا مع التهجير المناسب، فعلى سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class Assembly &lt; ApplicationRecord
  has_and_belongs_to_many :parts
end
 
class Part &lt; ApplicationRecord
  has_and_belongs_to_many :assemblies
end
</code></pre>

<p>
	يجب أن تدعم هذه بالتهجير لإنشاء جدول <code>assemblies_parts</code>، والذي يجب أن يُنشئ دون مفتاح رئيسي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class CreateAssembliesPartsJoinTable &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :assemblies_parts, id: false do |t|
      t.integer :assembly_id
      t.integer :part_id
    end
 
    add_index :assemblies_parts, :assembly_id
    add_index :assemblies_parts, :part_id
  end
end
</code></pre>

<p>
	مررنا <code>id: false</code> إلى <code>create_table</code> لأن الجدول لا يُمثل نموذج، وهذا ضروري للارتباط ليعمل بشكل صحيح.<br>
	قد تلاحظ تصرفات غريبة في ارتباط <code>has_and_belongs_to_many</code> مثل مُعرّفات نموذج سيئة أو استثناءات حول تضارب المعرّفات، لكنها نادرا ما تحدث.<br>
	يمكنك استخدام أسلوب <code>create_join_table</code> أيضًا.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class CreateAssembliesPartsJoinTable &lt; ActiveRecord::Migration[5.0]
  def change
    create_join_table :assemblies, :parts do |t|
      t.index :assembly_id
      t.index :part_id
    end
  end
end
</code></pre>

<h3 id="التحكم-في-نطاق-scope-الارتباط">
	3.4 التحكم في نطاق scope الارتباط
</h3>

<p>
	تبحث الارتباطات افتراضيا عن الكائنات ضمن نطاق الوحدة (module) الحالية، وهذا جيد عندما تعلن عن نماذج Active Record ضمن الوحدة، فعلى سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>module MyApplication
  module Business
    class Supplier &lt; ApplicationRecord
       has_one :account
    end
 
    class Account &lt; ApplicationRecord
       belongs_to :supplier
    end
  end
end
</code></pre>

<p>
	وهذا سيعمل بشكل صحيح، لأن كل من صنف المُورّد والحساب تم تعريفهما داخل نفس النطاق، لكن الشيفرة البرمجية التالية لن تعمل، لأنه عُرّف المُورّد والحساب في نطاقات مختلفة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>module MyApplication
  module Business
    class Supplier &lt; ApplicationRecord
       has_one :account
    end
  end
 
  module Billing
    class Account &lt; ApplicationRecord
       belongs_to :supplier
    end
  end
end
</code></pre>

<p>
	لربط نموذج مع نموذج في مساحة اسم (<code>namespace</code>) مختلفة يجب عليك تحديد اسم الصنف كاملا في إعلان الارتباط:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>module MyApplication
  module Business
    class Supplier &lt; ApplicationRecord
       has_one :account,
        class_name: "MyApplication::Billing::Account"
    end
  end
 
  module Billing
    class Account &lt; ApplicationRecord
       belongs_to :supplier,
        class_name: "MyApplication::Business::Supplier"
    end
  end
end
</code></pre>

<h3 id="الارتباطات-ثنائية-الاتجاه">
	3.5 الارتباطات ثنائية الاتجاه
</h3>

<p>
	من الطبيعي أن تعمل الارتباطات في كلا الاتجاهين، وهذا الأمر يتطلب إعلان في نموذجين مختلفين:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class Author &lt; ApplicationRecord
  has_many :books
end
 
class Book &lt; ApplicationRecord
  belongs_to :author
end
</code></pre>

<p>
	سيحاول Active Record تلقائيا معرفة أن هذيّن النموذجين يشتركان في ارتباط ثنائي الاتجاه بناءا على اسم الارتباط، وبهذه الطريقة سيحمّل Active Record نسخة واحدة من كائن Author وبذلك سيصبح تطبيقك أكثر كفاءة ويمنع البيانات غير المتناسقة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>a = Author.first
b = a.books.first
a.first_name == b.author.first_name # =&gt; true
a.first_name = 'David'
a.first_name == b.author.first_name # =&gt; true
</code></pre>

<p>
	يدعم Active Record التعرف التلقائي لأغلب الارتباطات مع الأسماء القياسيّة، ومع ذلك لن يُعرّف Active Record الارتباطات ثنائية الاتجاه تلقائيا إذا احتوت على أي من الخيارات التالية:
</p>

<ul>
<li>
		<code>conditions:</code>
	</li>
	<li>
		<code>through:</code>
	</li>
	<li>
		<code>polymorphic:</code>
	</li>
	<li>
		<code>class_name:</code>
	</li>
	<li>
		<code>foreign_key</code>
	</li>
</ul>
<p>
	على سبيل المثال، فكر في إعلان النماذج التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class Author &lt; ApplicationRecord
  has_many :books
end
 
class Book &lt; ApplicationRecord
  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end
</code></pre>

<p>
	لن يتعرف Active Record تلقائيا على الارتباط ثنائي الاتجاه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # =&gt; true
a.first_name = 'David'
a.first_name == b.writer.first_name # =&gt; false
</code></pre>

<p>
	يوفر Active Record خيار <code>:inverse_of</code> حتى تتمكن من الإعلان الارتباطات ثنائية الاتجاه بشكل صريح:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>class Author &lt; ApplicationRecord
  has_many :books, inverse_of: 'writer'
end
 
class Book &lt; ApplicationRecord
  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end
</code></pre>

<p>
	من خلال تضمين خيار <code>:inverse_of</code> في إعلان ارتباط <code>has_many</code>، سيتعرّف Active Record على ارتباط ثنائي الاتجاه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2022_8" style="">
<code>a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # =&gt; true
a.first_name = 'David'
a.first_name == b.writer.first_name # =&gt; true
</code></pre>

<p>
	توجد بعض القيود على دعم <code>inverse_of:</code> :
</p>

<ul>
<li>
		لا تعمل مع ارتباطات <code>through:</code>
	</li>
	<li>
		لا تعمل مع ارتباطات <code>polymorphic:</code>
	</li>
	<li>
		لا تعمل مع ارتباطات <code>as:</code>
	</li>
</ul>
<p>
	وسنتابع في الدرس القادم التعرّف على مرجع الارتباط المفصّل.
</p>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/association_basics.html" rel="external nofollow">Ruby on Rails</a>
</p>
]]></description><guid isPermaLink="false">621</guid><pubDate>Sun, 18 Feb 2018 17:01:01 +0000</pubDate></item><item><title>Active Record Associations: &#x627;&#x644;&#x627;&#x631;&#x62A;&#x628;&#x627;&#x637;&#x627;&#x62A; &#x648;&#x623;&#x646;&#x648;&#x627;&#x639;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-associations-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-r617/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8ee37b4ee_11-2(1).png.6a40f887d1cbb801fff9bb6ceb4d20ac.png" /></p>

<p>
	سنتعرّف في سلسلة الدروس هذه والتي تبدأ بهذا الدرس على ارتباطات Active Record في روبي أند ريلز وسنبدأ أولًا بمعرفة لماذا الارتباطات:
</p>

<h2>
	<a id="1___Associations_0" rel=""></a>1 لماذا الارتباطات Associations؟
</h2>

<p>
	في Rails، الارتباط association هو اتصال بين نموذجي Active Record. لماذا نحتاج إلى هذه الارتباطات بين النماذج؟ وذلك لأن العمليات المشتركة ستصبح أبسط وأسهل في الشيفرة البرمجية، على سبيل المثال، اعتبر أن تطبيق Rails بسيط يتضمن نموذج للمؤلفين ونموذج للكتب، كل مؤلف قد يملك العديد من الكتب، وبدون الارتباطات، سيشبه إعلان النموذج هذا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Author</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">
 
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Book</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	الآن، لنفترض أننا نريد إضافة كتاب جديد للمؤلف الحالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>@book = Book.create(published_at: Time.now, author_id: @author.id)
</code></pre>

<p>
	أو حذف المؤلف مع جميع كتبه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>@books = Book.where(author_id: @author.id)
@books.each do |book|
  book.destroy
end
@author.destroy
</code></pre>

<p>
	باستخدام ارتباطات Active Record، يمكننا تبسيط هذه العملية (وغيرها) عن طريق إعلان لـ Rails نخبره بوجود اتصال بين النموذجين، وهذه الشيفرة البرمجية معدلة لإعداد المؤلفين والكتب:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Author &lt; ApplicationRecord
  has_many :books, dependent: :destroy
end
 
class Book &lt; ApplicationRecord
  belongs_to :author
end
</code></pre>

<p>
	وبهذا، ستصبح عملية إنشاء كتاب لمؤلف معين أسهل:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>@book = @author.books.create(published_at: Time.now)
</code></pre>

<p>
	بالإضافة إلى أن عملية حذف المؤلف مع جميع كتبه أسهل بكثير:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>@author.destroy
</code></pre>

<p>
	لمزيد من المعلومات حول الأنواع المختلفة للارتباطات، اقرأ القسم التالي من هذا الدليل، وستجد بعدها بعض النصائح والحيل للعمل مع الارتباطات، ومن ثم مرجع كامل للنماذج وخيارات الارتباطات في Rails.
</p>

<h2>
	<a id="2___Associations_41" rel=""></a>2 أنواع الارتباطات Associations
</h2>

<p>
	يدعم Rails ستة أنواع من الارتباطات Associations:
</p>

<ul>
<li>
		<code>belongs_to</code>
	</li>
	<li>
		<code>has_one</code>
	</li>
	<li>
		<code>has_many</code>
	</li>
	<li>
		<code>has_many :through</code>
	</li>
	<li>
		<code>has_one :through</code>
	</li>
	<li>
		<code>has_and_belongs_to_many</code>
	</li>
</ul>
<p>
	تنفّذ الارتباطات Association باستخدام نداءات نمط ماكرو (macro-style) بحيث يمكنك إضافة ميزات إلى نماذج، فعلى سبيل المثال، من خلال إعلان أن نموذج ينتمي <code>belongs_to</code> إلى آخر، ستجعل Rails يحافظ على بيانات المفتاح الرئيسي والمفتاح الخارجي (Primary Key-Foreign Key) بين مثيلات النموذجين، ويمكنك الحصول على عدد الأساليب المضافة إلى نموذجك.
</p>

<p>
	في ما تبقى من هذا الدليل، ستتعلم كيف تُعلن وتستخدم أشكال مختلفة من الارتباطات، لكن أولا، مقدمة قصيرة إلى الحالات التي تتناسب معها كل نوع من الارتباطات.
</p>

<h3>
	<a id="21__belongs_to_54" rel=""></a>2.1 ارتباط <code>belongs_to</code>
</h3>

<p>
	يعيّن ارتباط <code>belongs_to</code> اتصال واحد لواحد (one-to-one) مع نموذج آخر، بحيث أن كل مثيل للنموذج المعلن “يرتبط” بمثيل واحد للنموذج الآخر، فعلى سبيل المثال، إذا كان التطبيق يتضمن مؤلفين وكتب وكل كتاب يرتبط فقط إلى مؤلف واحد، يمكنك إعلان نموذج الكتاب كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Book &lt; ApplicationRecord
  belongs_to :author
end
</code></pre>

<p style="text-align: center;">
	<img alt="01 (5).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26980" data-unique="9pjj2nqjy" src="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b5e375ba_01(5).png.b14b693c034b42324f5639c0e4b9f289.png"></p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong> يجب أن تستخدم ارتباطات belongs_to صيغة المفرد، فإذا استخدمت صياغة الجمع في المثال أعلاه لارتباط المؤلف مع نموذج الكتاب، ستظهر لك رسالة "<code>uninitialized constant Book::Authors</code>" وذلك لأن Rails يستنتج اسم الصنف من اسم الارتباط، إذا جُمع اسم الارتباط عن طريق الخطأ فالأصناف المستنسخة ستجمع عن طريق الخطأ.
		</p>
	</div>
</blockquote>

<p>
	عملية التهجير ستشبه هذه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreateBooks &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :authors do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :books do |t|
      t.belongs_to :author, index: true
      t.datetime :published_at
      t.timestamps
    end
  end
end
</code></pre>

<h3>
	<a id="22__has_one_83" rel=""></a>2.2 ارتباط <code>has_one</code>
</h3>

<p>
	يعيّن ارتباط <code>has_one</code> أيضا اتصال واحد لواحد (one-to-one) مع نموذج آخر، لكن مع دلالات (semantics) -وعواقب- مختلفة، فيشير هذا الارتباط أن كل مثيل للنموذج يحتوي أو يمتلك مثيل لنموذج آخر فعلى سبيل المثال، إذا يملك كل مُورّد في تطبيقك حساب واحد فقط، سيشبه إعلان نموذج المورد هذا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Supplier &lt; ApplicationRecord
  has_one :account
end
</code></pre>

<p style="text-align: center;">
	<img alt="02 (4).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26979" data-unique="fcjim92ti" src="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b5c76c62_02(4).png.c63e0c7f458f80b6a3d629ec823fea1a.png"></p>

<p>
	عملية التهجير ستشبه هذه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreateSuppliers &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :suppliers do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :accounts do |t|
      t.belongs_to :supplier, index: true
      t.string :account_number
      t.timestamps
    end
  end
end
</code></pre>

<p>
	بناءََ على حالة الاستخدام، ستحتاج إلى إنشاء فهرس فريد و/أو إلى قيد مفتاح خارجي (<code>foreign key</code>) على عمود المُورّد لجدول الحسابات، في هذه الحالة، سيشبه تعريف العمود لهذا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>create_table :accounts do |t|
  t.belongs_to :supplier, index: { unique: true }, foreign_key: true
  # ...
end
</code></pre>

<h3>
	<a id="23__has_many_117" rel=""></a>2.3 ارتباط <code>has_many</code>
</h3>

<p>
	يشير ارتباط <code>has_many</code> إلى اتصال واحد إلى الكثير (one-to-many) مع نموذج آخر، ستجد في الكثير من الأحيان هذا الارتباط في الجانب الآخر لارتباط <code>belongs_to</code>، وهذا الارتباط يشير إلى أن كل مثيل للنموذج يملك صفر مثيل أو أكثر للنموذج الآخر، فعلى سبيل المثال، في التطبيق الذي يحتوي على المؤلفين وكتب، يمكنك الإعلان عن نموذج المؤلف كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Author &lt; ApplicationRecord
  has_many :books
end
</code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong> يُجمع – صياغة الجمع - اسم النموذج الآخر عند إعلان ارتباط has_many.
		</p>
	</div>
</blockquote>

<p style="text-align: center;">
	<img alt="03 (5).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26981" data-unique="70s3nux8x" src="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b5fa772c_03(5).png.3f8faa03df78093b68de8948f1d1067a.png"></p>

<p>
	عملية التهجير ستشبه هذه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreateAuthors &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :authors do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :books do |t|
      t.belongs_to :author, index: true
      t.datetime :published_at
      t.timestamps
    end
  end
end
</code></pre>

<h3>
	<a id="24__has_many_through_147" rel=""></a>2.4 ارتباط <code>has_many :through</code>
</h3>

<p>
	يُستخدم ارتباط <code>has_many :through</code> لإنشاء اتصال كثير إلى كثير(many-to-many) مع نموذج آخر، فهذا النموذج يشير إلى أن النموذج المُعلن يمكن أن يقابل صفر مثيل أو أكثر من نموذج آخر من خلال نموذج ثالث، فعلى سبيل المثال، فكر في العمل الطبي حيث يحدد المرضى مواعيد لرؤية الأطباء، فسيُعلن الارتباط كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Physician &lt; ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end
 
class Appointment &lt; ApplicationRecord
  belongs_to :physician
  belongs_to :patient
end
 
class Patient &lt; ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end
</code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="26982" href="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b60c96cc_04(4).png.c6aa35d0855aa0af025ab5ef57fd0cdf.png" rel=""><img alt="04 (4).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26982" data-unique="hx1btdrb6" src="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b61e8cfc_04(4).thumb.png.e3aeff1cd806298a8b24065a3581f2fc.png"></a>
</p>

<p>
	عملية التهجير ستشبه هذه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreateAppointments &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :physicians do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :patients do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :appointments do |t|
      t.belongs_to :physician, index: true
      t.belongs_to :patient, index: true
      t.datetime :appointment_date
      t.timestamps
    end
  end
end
</code></pre>

<p>
	يمكنك إدارة مجموعة نماذج المنضمّة عن طريق أساليب ارتباط <code>has_many</code>، فعلى سبيل المثال، إذا عيّنت هذا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>physician.patients = patients
</code></pre>

<p>
	فإنه سينشئ النماذج المنضمّة تلقائيا للكائنات المرتبطة حديثا، إذا كان بعضها موجود سابقا وفُقِد حاليا، فستُحذف صفوف الضم الخاصة به تلقائيا.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تنبيه:</strong> تحذف النماذج المنضمّة تلقائيا بشكل مباشر، فلن تشتغل دالة الاستدعاء للتدمير.
		</p>
	</div>
</blockquote>

<p>
	يمكنك الاستفادة من ارتباط <code>has_many :through</code> لإنشاء "اختصارات” من خلال ارتباطات <code>has_many</code> متداخلة، فعلى سبيل المثال، إذا كان مستند يملك أقسام عديدة، ويحتوي القسم على فقرات، فقد تحتاج في بعض الأحيان إلى الحصول على مجموعة بسيطة من جميع الفقرات في المستند، ويمكنك إنشاء ذلك عن طريق:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Document &lt; ApplicationRecord
  has_many :sections
  has_many :paragraphs, through: :sections
end
 
class Section &lt; ApplicationRecord
  belongs_to :document
  has_many :paragraphs
end
 
class Paragraph &lt; ApplicationRecord
  belongs_to :section
end
</code></pre>

<p>
	سيفهم Rails هذا الآن عن طريق محدد <code>through: :sections</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>@document.paragraphs
</code></pre>

<h3>
	<a id="25__has_one_through_221" rel=""></a>2.5 ارتباط <code>has_one :through</code>
</h3>

<p>
	تنشئ ارتباطات <code>has_one :through</code> اتصال واحد لواحد (one-to-one) مع نموذج آخر، هذا الارتباط يشير إلى أن النموذج المُعلن عنه يمكن أن يقابل مع مثيل من نموذج آخر من خلال نموذج آخر، على سبيل المثال، إذا كان يملك كل مُورّد حساب واحد، وكل حساب مرتبط بسجل حساب واحد، فسيكون نموذج المُورّد كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Supplier &lt; ApplicationRecord
  has_one :account
  has_one :account_history, through: :account
end
 
class Account &lt; ApplicationRecord
  belongs_to :supplier
  has_one :account_history
end
 
class AccountHistory &lt; ApplicationRecord
  belongs_to :account
end
</code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="26983" href="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b6397c07_05(4).png.d6937c4275c1cafcfbba3478715883cd.png" rel=""><img alt="05 (4).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26983" data-unique="ucwjf0cxz" src="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b64ac704_05(4).thumb.png.a567c4d07dd973c2c58a197e0dc4cb5c.png"></a>
</p>

<p>
	عملية التهجير ستشبه هذه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreateAccountHistories &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :suppliers do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :accounts do |t|
      t.belongs_to :supplier, index: true
      t.string :account_number
      t.timestamps
    end
 
    create_table :account_histories do |t|
      t.belongs_to :account, index: true
      t.integer :credit_rating
      t.timestamps
    end
  end
end
</code></pre>

<h3>
	<a id="26__has_and_belongs_to_many_263" rel=""></a>2.6 الارتباط <code>has_and_belongs_to_many</code>
</h3>

<p>
	ينشئ ارتباط <code>has_and_belongs_to_many</code> اتصال الكثير إلى الكثير many-to-many مباشر مع نموذج آخر بدون تدخل نموذج ثالث، فعلى سبيل المثال، إذا كان تطبيقك يحتوي على تجميعات وأجزاء، ستجد أجزاء عديدة مع كل تجميع وكل جزء يظهر في الكثير من التجميعات، فيمكنك إعلان هذا النموذج كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Assembly &lt; ApplicationRecord
  has_and_belongs_to_many :parts
end
 
class Part &lt; ApplicationRecord
  has_and_belongs_to_many :assemblies
end
</code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="26984" href="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b65920bf_06(5).png.9fe838d6eb8f509811077fed9f150646.png" rel=""><img alt="06 (5).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26984" data-unique="uhm9xdww2" src="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b669007d_06(5).thumb.png.83d4c42bea23fcdd27f7413ce272cd97.png"></a>
</p>

<p>
	عملية التهجير ستشبه هذه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreateAssembliesAndParts &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :assemblies do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :parts do |t|
      t.string :part_number
      t.timestamps
    end
 
    create_table :assemblies_parts, id: false do |t|
      t.belongs_to :assembly, index: true
      t.belongs_to :part, index: true
    end
  end
end
</code></pre>

<h3>
	<a id="27___belongs_to__has_one_297" rel=""></a>2.7 الاختيار بين <code>belongs_to</code> و <code>has_one</code>
</h3>

<p>
	إذا أردت إنشاء علاقة واحد إلى واحد (one-to-one) بين نموذجين، فستحتاج إلى إضافة <code>belongs_to to</code> إلى أحدهم و has_one إلى الآخر، فكيف ستعرف لمن تضيف هذا؟<br>
	يمكنك تمييز ذلك عن طريق المكان الذي وضعت فيه المفتاح الخارجي (ستكون في الجدول الصنف الذي أعلنت فيه ارتباط <code>belongs_to</code>)، لكن يجب عليك أن تفكر في معنى الفعلي للبيانات، فعلاقة <code>has_one</code> تعني أنه يوجد شيء خاص بك، أي أن جزء منه يعود لك، فعلى سبيل المثال، من المنطقي القول بأن المُورّد يملك حساب على أن الحساب يملك مُورّد، وهذا يعني أن العلاقة الصحيحة مشابهة لهذه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Supplier &lt; ApplicationRecord
  has_one :account
end
 
class Account &lt; ApplicationRecord
  belongs_to :supplier
end
</code></pre>

<p>
	عملية التهجير ستشبه هذه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreateSuppliers &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :suppliers do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :accounts do |t|
      t.integer :supplier_id
      t.string  :account_number
      t.timestamps
    end
 
    add_index :accounts, :supplier_id
  end
end
</code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong> يمكنك جعل اسم المفتاح الخارجي واضح وصريح عن طريق استخدام <code>t.integer :supplier_id</code>، في الإصدار Rails الحالي، يمكنك استخدام <code>t.references :supplier</code> بدلاً من ذلك.
		</p>
	</div>
</blockquote>

<h3>
	<a id="28___has_many_through_has_and_belongs_to_many_330" rel=""></a>2.8 الاختيار بين <code>has_many :through</code> و <code>has_and_belongs_to_many</code>
</h3>

<p>
	يوفر Rails طريقتين لإعلان علاقة الكثير إلى الكثير (many-to-many) بين النماذج، أبسط طريقة هي عن طريق استخدام <code>has_and_belongs_to_many</code>، والتي تمكنك من إنشاء هذا الارتباط مباشرة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Assembly &lt; ApplicationRecord
  has_and_belongs_to_many :parts
end
 
class Part &lt; ApplicationRecord
  has_and_belongs_to_many :assemblies
end
</code></pre>

<p>
	الطريقة الثانية هي عن طريق استخدام <code>has_many :through</code> لجعل الارتباط غير مباشرة، عن طريق ضم نموذج:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Assembly &lt; ApplicationRecord
  has_many :manifests
  has_many :parts, through: :manifests
end
 
class Manifest &lt; ApplicationRecord
  belongs_to :assembly
  belongs_to :part
end
 
class Part &lt; ApplicationRecord
  has_many :manifests
  has_many :assemblies, through: :manifests
end
</code></pre>

<p>
	ببساطة، إذا أردت العمل مع نموذج العلاقة ككيان مستقل، يجب عليك إنشاء علاقة <code>has_many :through</code>، وإذا لم تحتاج إلى القيام بأي شيء مع نموذج العلاقة، سيكون من الأسهل إنشاء علاقة <code>has_and_belongs_to_many</code> (لا تنسى إنشاء جدول الضم joining table في قاعدة البيانات).<br>
	يجب عليك استخدام <code>has_many :through</code> إذا احتجت إلى عمليات تحقق validations، دوال استدعاء callbacks أو سمات attributes إضافيَة في نموذج الضم.
</p>

<h3>
	<a id="29____Polymorphic_Associations_360" rel=""></a>2.9 ارتباطات متعددة الأشكال Polymorphic Associations
</h3>

<p>
	من المواضيع المتقدمة قليلا في الارتباطات، هي الارتباطات متعددة الأشكال، فعن طريقها، يمكن للنموذج أن يرتبط بأكثر من نموذج بارتباط واحد، فعلى سبيل المثال، قد تملك نموذج صورة التي تنتمي إلى نموذج الموظف أو إلى نموذج المنتج، ويمكنك الإعلان عن ذلك عن طريق التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Picture &lt; ApplicationRecord
  belongs_to :imageable, polymorphic: true
end
 
class Employee &lt; ApplicationRecord
  has_many :pictures, as: :imageable
end
 
class Product &lt; ApplicationRecord
  has_many :pictures, as: :imageable
end
</code></pre>

<p>
	فكر في إعلان <code>belongs_to</code> متعدد الأشكال على أنه إنشاء لواجهة يمكن لأي نموذج آخر أن يستخدمها، من مثيل نموذج Employee، يمكنك استرداد مجموع من الصور عن طريق:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code> @employee.pictures.
</code></pre>

<p>
	وبنفس الطريقة يمكنك استرداد <code>product.pictures@</code>.<br>
	إذا كنت تملك مثيل من نموذج الصورة، فيمكنك الحصول على الأب (parent) عن طريق <code>picture.imageable@</code>، ولتحقيق ذلك، تحتاج إلى إعلان كل من عمود مفتاح خارجي وعمود النوع في النموذج الذي أعلنت فيه واجهة متعددة الأشكال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreatePictures &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :pictures do |t|
      t.string  :name
      t.integer :imageable_id
      t.string  :imageable_type
      t.timestamps
    end
 
    add_index :pictures, [:imageable_type, :imageable_id]
  end
end
</code></pre>

<p>
	يمكن تبسيط عملية التهجير عن طريق استخدام <code>t.references</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreatePictures &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :pictures do |t|
      t.string :name
      t.references :imageable, polymorphic: true, index: true
      t.timestamps
    end
  end
end
</code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="26985" href="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b67979cb_07(4).png.4dcc914d89ab83f2b880b570379ab9bc.png" rel=""><img alt="07 (4).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26985" data-unique="rdg17if1r" src="https://academy.hsoub.com/uploads/monthly_2018_02/5a7c8b68d7261_07(4).thumb.png.536c774d937b681f6e9c8888b5175103.png"></a>
</p>

<h3>
	<a id="210___Self_Joins_409" rel=""></a>2.10 ضم ذاتي Self Joins
</h3>

<p>
	عند تصميم نموذج بيانات، ستجد في بعض الأحيان أن العلاقة يجب أن تكون مرتبطة بنفسها، فعلى سبيل المثال، قد تريد تخزين جميع الموظفين في نموذج قاعدة بيانات واحدة، لكن يجب تقدر أيضا على تتبع العلاقات مثل علاقة المدير بالمرؤوسين، وهذه الحالة يمكن إنشاءها عن طريق ارتباطات الضم الذاتي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class Employee &lt; ApplicationRecord
  has_many :subordinates, class_name: "Employee",
                          foreign_key: "manager_id"
 
  belongs_to :manager, class_name: "Employee"
end
</code></pre>

<p>
	مع هذا الإعداد، يمكنك استرداد <code>employee.subordinates@</code> و <code>employee.manager@</code>.<br>
	في عمليات التهجير/المخطط، ستحتاج إلى إضافة عمود المرجع إلى نفس النموذج.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4895_7" style="">
<code>class CreateEmployees &lt; ActiveRecord::Migration[5.0]
  def change
    create_table :employees do |t|
      t.references :manager, index: true
      t.timestamps
    end
  end
end
</code></pre>

<p>
	وسنتابع التعرّف على الإرتباطات في Active Record في الدروس اللاحقة.
</p>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/association_basics.html" rel="external nofollow">Ruby on Rails</a>
</p>
]]></description><guid isPermaLink="false">617</guid><pubDate>Thu, 08 Feb 2018 17:57:22 +0000</pubDate></item><item><title>&#x62F;&#x648;&#x627;&#x644; &#x627;&#x633;&#x62A;&#x62F;&#x639;&#x627;&#x621; Active Record</title><link>https://academy.hsoub.com/programming/ruby/rails/%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D8%B3%D8%AA%D8%AF%D8%B9%D8%A7%D8%A1-active-record-r613/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_01/5a701fb3ddb7d_04(1).png.0d40c6bc7056256122edbec315a4e7ae.png" /></p>

<p>
	ستتعرّف في هذا الدرس على دورة حياة كائنات Active Record، وستتعلم:
</p>

<ul>
<li>
		دورة حياة كائنات Active Record.
	</li>
	<li>
		كيف تنشئ أساليب دوال الاستدعاء (callback methods) التي تستجيب إلى أحداث في دورة حياة الكائن.
	</li>
	<li>
		كيف تنشئ أصناف خاصة التي تجمع السلوك المشترك لدوال الاستدعاء (callbacks).
	</li>
</ul>
<h2>
	<a id="1____6" rel=""></a>1- دورة حياة الكائن
</h2>

<p>
	يمكن إنشاء، تحديث وتدمير الكائنات أثناء عمل تطبيق Rails، ويوفر Active Record طُرق تُمكنك من التحكم بالتطبيق وبياناته في دورة حياة الكائن .<br>
	يسمح لك دوال الاستدعاء بإطلاق منطقي (trigger logic) قبل أو بعد تغيير حالة الكائن.
</p>

<h2>
	<a id="2______callbacks_9" rel=""></a>2- نظرة عامة على دوال الاستدعاء callbacks
</h2>

<p>
	دوال الاستدعاء (callbacks) هي أساليب تُستدعى في لحظات معينة من دورة حياة الكائن وتمكنك من كتابة شيفرة برمجية تعمل عند إنشاء، حفظ، تحديث، حذف، تحقق من صحة أو تحميل كائن Active Record من قاعدة البيانات.
</p>

<h3>
	<a id="21____11" rel=""></a>2-1 تسجيل دوال الاستدعاء
</h3>

<p>
	تحتاج إلى تسجيل دوال الاستدعاء المتوفر حتى تتمكن من استخدامه، فيمكنك وضع دوال الاستدعاء كأساليب عادية، واستخدام أسلوب صنف نمط ماكرو (macro-style) لتسجيلهم كدوال استدعاء:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">login</span><span class="pun">,</span><span class="pln"> </span><span class="pun">:</span><span class="pln">email</span><span class="pun">,</span><span class="pln"> presence</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
 
  before_validation </span><span class="pun">:</span><span class="pln">ensure_login_has_a_value
 
  private
    </span><span class="kwd">def</span><span class="pln"> ensure_login_has_a_value
      </span><span class="kwd">if</span><span class="pln"> login</span><span class="pun">.</span><span class="kwd">nil</span><span class="pun">?</span><span class="pln">
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">login </span><span class="pun">=</span><span class="pln"> email </span><span class="kwd">unless</span><span class="pln"> email</span><span class="pun">.</span><span class="pln">blank</span><span class="pun">?</span><span class="pln">
      </span><span class="kwd">end</span><span class="pln">
    </span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	يمكن لأساليب صنف نمط ماكرو (macro-style) تلقي كتلة (block) لذلك استخدم هذا النمط إذا كانت الشيفرة البرمجية داخل الكتلة قصيرة بحيث يمكن وضعها في سطر واحد:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class User &lt; ApplicationRecord
  validates :login, :email, presence: true
 
  before_create do
    self.name = login.capitalize if name.blank?
  end
end
</code></pre>

<p>
	يمكنك تسجيل دوال الاستدعاء ليعمل فقط على بعض أحداث دورة حياة الكائن:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class User &lt; ApplicationRecord
  before_validation :normalize_name, on: :create
 
  # :on takes an array as well
  after_validation :set_location, on: [ :create, :update ]
 
  private
    def normalize_name
      self.name = name.downcase.titleize
    end
 
    def set_location
      self.location = LocationService.query(self)
    end
end
</code></pre>

<p>
	من الممارسات الجيدة أن تعلن أساليب دوال الاستدعاء كخاص، لأنه يمكن استدعاؤه من خارج النموذج (Model) إذا كان عامََا وبهذا تنتهك مبدأ تغليف الكائن (object encapsulation).
</p>

<h2>
	<a id="3____57" rel=""></a>3- دوال الاستدعاء المتوفرة
</h2>

<p>
	هذه قائمة بجميع دوال استدعاء Active Record المتوفر وهو مرتب بنفس ترتيب استدعاءه خلال العمليات:
</p>

<h3>
	<a id="31___59" rel=""></a>3-1 إنشاء كائن
</h3>

<ul>
<li>
		<code>before_validation</code>
	</li>
	<li>
		<code>after_validation</code>
	</li>
	<li>
		<code>before_save</code>
	</li>
	<li>
		<code>around_save</code>
	</li>
	<li>
		<code>before_create</code>
	</li>
	<li>
		<code>around_create</code>
	</li>
	<li>
		<code>after_create</code>
	</li>
	<li>
		<code>after_save</code>
	</li>
	<li>
		<code>after_commit/after_rollback</code>
	</li>
</ul>
<h3>
	<a id="32___69" rel=""></a>3-2 تحديث كائن
</h3>

<ul>
<li>
		<code>before_validation</code>
	</li>
	<li>
		<code>after_validation</code>
	</li>
	<li>
		<code>before_save</code>
	</li>
	<li>
		<code>around_save</code>
	</li>
	<li>
		<code>before_update</code>
	</li>
	<li>
		<code>around_update</code>
	</li>
	<li>
		<code>after_update</code>
	</li>
	<li>
		<code>after_save</code>
	</li>
	<li>
		<code>after_commit/after_rollback</code>
	</li>
</ul>
<h3>
	<a id="33___79" rel=""></a>3-3 تدمير كائن
</h3>

<ul>
<li>
		<code>before_destroy</code>
	</li>
	<li>
		<code>around_destroy</code>
	</li>
	<li>
		<code>after_destroy</code>
	</li>
	<li>
		<code>after_commit/after_rollback</code>
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تحذير:</strong><br>
			تعمل <code>after_save</code> عند الإنشاء والتحديث لكن دائما بعد دوال الاستدعاء <code>after_create</code> و <code>after_update</code> مهما كان ترتيب تنفيذ نداءات ماكرو (macro calls).
		</p>
	</div>
</blockquote>

<h3>
	<a id="34_after_initialize__after_find_88" rel=""></a>3-4 after_initialize و after_find
</h3>

<p>
	ستُستدعى دالة الاستدعاء <code>after_initialize</code> عند إنشاء كائن Active Record، إما مباشرة عن طريق <code>new</code> أو عند تحميل السجل <code>record</code> من قاعدة البيانات، ومن المستحسن تجنب الحاجة إلى تجاوز إنشاء أسلوب Active Record مباشرة.<br>
	ستُستدعى دالة الاستدعاء <code>after_find</code> في كل مرة يُحمّل فيها Active Record سجل من قاعدة البيانات، وستُستدعى <code>after_find</code> قبل <code>after_initialize</code> إذا تم تعريفهما.
</p>

<p>
	لا يملك دوال الاستدعاء <code>after_initialize</code> و<code>after_find</code> نظرائهم من نوع <code>before_*</code>، لكن يمكن تسجيلهم كباقي دوال الاستدعاء Active Record.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class User &lt; ApplicationRecord
  after_initialize do |user|
    puts "You have initialized an object!"
  end
 
  after_find do |user|
    puts "You have found an object!"
  end
end
 
&gt;&gt; User.new
You have initialized an object!
=&gt; #&lt;User id: nil&gt;
 
&gt;&gt; User.first
You have found an object!
You have initialized an object!
=&gt; #&lt;User id: 1&gt;
</code></pre>

<h3>
	<a id="35_after_touch_114" rel=""></a>3-5 after_touch
</h3>

<p>
	ستُستدعى دالة الاستدعاء <code>after_touch</code> كلما يُلمس (touch) كائن Active Record.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class User &lt; ApplicationRecord
  after_touch do |user|
    puts "You have touched an object"
  end
end
 
&gt;&gt; u = User.create(name: 'Kuldeep')
=&gt; #&lt;User id: 1, name: "Kuldeep", created_at: "2013-11-25 12:17:49", updated_at: "2013-11-25 12:17:49"&gt;
 
&gt;&gt; u.touch
You have touched an object
=&gt; true
</code></pre>

<p>
	يمكن استخدام هذه الدالة جنبا إلى جنب مع <code>belongs_to</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class Employee &lt; ApplicationRecord
  belongs_to :company, touch: true
  after_touch do
    puts 'An Employee was touched'
  end
end
 
class Company &lt; ApplicationRecord
  has_many :employees
  after_touch :log_when_employees_or_company_touched
 
  private
  def log_when_employees_or_company_touched
    puts 'Employee/Company was touched'
  end
end
 
&gt;&gt; @employee = Employee.last
=&gt; #&lt;Employee id: 1, company_id: 1, created_at: "2013-11-25 17:04:22", updated_at: "2013-11-25 17:05:05"&gt;
 
# triggers @employee.company.touch
&gt;&gt; @employee.touch
Employee/Company was touched
An Employee was touched
=&gt; true
</code></pre>

<h2>
	<a id="4____159" rel=""></a>4- تشغيل دوال الاستدعاء
</h2>

<p>
	هذه أساليب إطلاق (trigger) دوال الاستدعاء:
</p>

<ul>
<li>
		<code>create</code>
	</li>
	<li>
		<code>create!</code>
	</li>
	<li>
		<code>destroy</code>
	</li>
	<li>
		<code>destroy!</code>
	</li>
	<li>
		<code>destroy_all</code>
	</li>
	<li>
		<code>save</code>
	</li>
	<li>
		<code>save!</code>
	</li>
	<li>
		<code>save(validate: false)</code>
	</li>
	<li>
		<code>toggle!</code>
	</li>
	<li>
		<code>update_attribute</code>
	</li>
	<li>
		<code>update</code>
	</li>
	<li>
		<code>update!</code>
	</li>
	<li>
		<code>Valid?</code>
	</li>
</ul>
<p>
	بالإضافة إلى ذلك، تُطلق (trigger) دالة الاستدعاء <code>after_find</code> عن طريق أساليب finder التالية:
</p>

<ul>
<li>
		<code>all</code>
	</li>
	<li>
		<code>first</code>
	</li>
	<li>
		<code>find</code>
	</li>
	<li>
		<code>find_by</code>
	</li>
	<li>
		<code>find_by_*</code>
	</li>
	<li>
		<code>find_by_*!</code>
	</li>
	<li>
		<code>find_by_sql</code>
	</li>
	<li>
		<code>last</code>
	</li>
</ul>
<p>
	تعمل دالة الاستدعاء <code>after_initialize</code> في كل مرة ينشئ فيها كائن صنف class جديد.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			أساليب find_by_* و find_by_*! هي finders حيوية تُولد تلقائيا لكل سمة، للمزيد من المعلومات راجع قسم Dynamic finders.
		</p>
	</div>
</blockquote>

<h2>
	<a id="5____188" rel=""></a>5- تجاوز دوال الاستدعاء
</h2>

<p>
	كما هو الحال مع عمليات التحقق (validation)، من الممكن أيضا تخطي دوال الاستدعاء عن طريق الأساليب التالية:
</p>

<ul>
<li>
		<code>decrement</code>
	</li>
	<li>
		<code>decrement_counter</code>
	</li>
	<li>
		<code>delete</code>
	</li>
	<li>
		<code>delete_all</code>
	</li>
	<li>
		<code>increment</code>
	</li>
	<li>
		<code>increment_counter</code>
	</li>
	<li>
		<code>toggle</code>
	</li>
	<li>
		<code>touch</code>
	</li>
	<li>
		<code>update_column</code>
	</li>
	<li>
		<code>update_columns</code>
	</li>
	<li>
		<code>update_all</code>
	</li>
	<li>
		<code>update_counters</code>
	</li>
</ul>
<p>
	يجب استخدام هذه الأساليب بحذر، لأنه قد يُحتفظ بقواعد الأعمال (generated) الهامة ومنطق التطبيق في دوال الاستدعاء، وقد يؤدي تجاوزها دون فهم الآثار المحتملة إلى بيانات غير صالحة.
</p>

<h2>
	<a id="6___204" rel=""></a>6- وقف التنفيذ
</h2>

<p>
	عند بدء تسجيل دوال استدعاء جديد لنماذجك، سيكون في قائمة الانتظار للتنفيذ، وستشمل هذه القائمة جميع عمليات تحقق (validations) النموذج الخاص بك، ودوال الاستدعاء المسجلة وعمليات قاعدة البيانات التي ستُنفّذ.<br>
	تُلف سلسلة (chain) دالة الاستدعاء بشكل كامل في العملية (transaction)، إذا أصدرت أي دالة استدعاء استثناء (exception)، فستتوقف السلسلة التي تعمل و يصدر ROLLBACK، وإذا أردت تعمد إيقاف السلسلة، استخدم:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>throw :abort
</code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تحذير:</strong><br>
			سيعاد إصدار أي استثناء (ما عدا <code>ActiveRecord::Rollback</code> أو <code>ActiveRecord::RecordInvalid</code>) عن طريق Rails بعد إيقاف سلسلة دالة الاستدعاء.<br>
			قد يكسر أي استثناء ماعدا <code>ActiveRecord::Rollback</code> أو <code>ActiveRecord::RecordInvalid</code> شيفرتك البرمجية التي لا تتوقع إصدار استثناء مثل أساليب <code>save</code> و <code>update_attributes</code> (والتي تُرجع في العادة قيمة منطقية <code>true</code> أو <code>false</code>).
		</p>
	</div>
</blockquote>

<h3>
	<a id="7____214" rel=""></a>7- دوال استدعاء علائقي
</h3>

<p>
	يعمل دوال الاستدعاء من خلال علاقات النموذج model، ويمكن تعريفه عن طريقه، لنفترض أن المستخدم لديه مقالات عديدة، ويجب حذف مقالات المستخدم في حالة حذف المستخدم، لنضف دالة استدعاء <code>after_destroy</code> إلى نموذج User لترتبط علائقيا بنموذج Model:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class User &lt; ApplicationRecord
  has_many :articles, dependent: :destroy
end
 
class Article &lt; ApplicationRecord
  after_destroy :log_destroy_action
 
  def log_destroy_action
    puts 'Article destroyed'
  end
end
 
&gt;&gt; user = User.first
=&gt; #&lt;User id: 1&gt;
&gt;&gt; user.articles.create!
=&gt; #&lt;Article id: 1, user_id: 1&gt;
&gt;&gt; user.destroy
Article destroyed
=&gt; #&lt;User id: 1&gt;
</code></pre>

<h2>
	<a id="8____238" rel=""></a>8- دوال الاستدعاء المشروط
</h2>

<p>
	كما هو الحال مع عمليات التحقق Validation، يمكن أيضا جعل أسلوب دالة الاستدعاء مشروط بشرط معين عن طريق استخدام خيارات <code>:if</code> و <code>:unless</code> والتي تأخذ رمز (symbol) أو Proc أو مصفوفة (Array).<br>
	يمكنك استخدام خيار <code>:if</code> عندما تريد تحديد شروط استدعاء دالة الاستدعاء، وإذا أردت وضع شروط لعدم استدعاء دالة الاستدعاء يمكنك استخدام <code>:unless</code>.
</p>

<h3>
	<a id="81__if__unless__Symbol_241" rel=""></a>8-1 استخدام :if و :unless مع Symbol
</h3>

<p>
	يمكنك ربط خيارات <code>:if</code> و <code>:unless</code> مع رمز (Symbol) مطابق لاسم الأسلوب الذي سيُستدعى قبل دالة الاستدعاء.<br>
	لن تُنفّذ دالة الاستدعاء عند استخدام خيار <code>:if</code> إذا ارجع الأسلوب <code>false</code>، وعند استخدام <code>:unless</code> لن تُنفّذ دالة الاستدعاء إذا أرجع الأسلوب <code>true</code>، وهذا الخيار هو الأكثر شيوعا.<br>
	من الممكن أيضا باستخدام هذا الشكل من التسجيل تسجيل <code>predicates</code> مختلفة، التي يتم استدعاؤها للتحقق ما إذا كان يجب تنفيذ دالة الاستدعاء.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class Order &lt; ApplicationRecord
  before_save :normalize_card_number, if: :paid_with_card?
End
</code></pre>

<h3>
	<a id="82__if__unless__Proc_250" rel=""></a>8-2 استخدام :if و :unless مع Proc
</h3>

<p>
	أخيرا، من الممكن ربط <code>:if</code> و <code>:unless</code> مع كائن Proc، وهذا الخيار هو الأنسب عند كتابة أساليب تحقق (validation) قصيرة، وفي العادة من سطر واحد:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class Order &lt; ApplicationRecord
  before_save :normalize_card_number,
    if: Proc.new { |order| order.paid_with_card? }
end
</code></pre>

<h3>
	<a id="83_____258" rel=""></a>8-3 شروط متعددة لدوال الاستدعاء
</h3>

<p>
	عند كتابة دوال استدعاء شرطي، من الممكن المزج بين <code>:if</code> و <code>:unless</code> في نفس إعلان دالة الاستدعاء:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class Comment &lt; ApplicationRecord
  after_create :send_email_to_author, if: :author_wants_emails?,
    unless: Proc.new { |comment| comment.article.ignore_comments? }
end
</code></pre>

<h2>
	<a id="9____266" rel=""></a>9- أصناف دالة الاستدعاء
</h2>

<p>
	في بعض الأحيان، تكون أساليب دالة الاستدعاء التي ستكتبها مفيدة وملائمة لإعادة استخدامها من قبل نماذج أخرى، لذا يوفر Active Record إمكانية إنشاء أصناف تغلف أساليب دالة الاستدعاء، لذا يصبح من السهل إعادة استخدامها.<br>
	هذا مثال أنشئنا فيه صنف مع دالة استدعاء <code>after_destroy</code> لنموذج <code>PictureFile</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class PictureFileCallbacks
  def after_destroy(picture_file)
    if File.exist?(picture_file.filepath)
      File.delete(picture_file.filepath)
    end
  end
end
</code></pre>

<p>
	عند الإعلان داخل صنف -كما في المثال أعلاه-، ستتلقى أساليب دالة الاستدعاء كائن النموذج كعامل، ونستطيع الآن استخدام صنف دالة الاستدعاء في النموذج:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class PictureFile &lt; ApplicationRecord
  after_destroy PictureFileCallbacks.new
end
</code></pre>

<p>
	لاحظ أننا بحاجة إلى إنشاء كائن <code>PictureFileCallbacks</code> جديد لأننا أعلنا دالة الاستدعاء الخاصة بنا على أنها مثيل أسلوب(instance method) ،وستستفيد من هذا خاصة إذا استخدمت دوال الاستدعاء حالة الكائن المثيل، ومع ذلك، في الكثير من الأحيان، سيكون من المنطقي إعلان دوال الاستدعاء كأساليب الصنف:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code> class PictureFileCallbacks
  def self.after_destroy(picture_file)
    if File.exist?(picture_file.filepath)
      File.delete(picture_file.filepath)
    end
  end
end
</code></pre>

<p>
	لن يكون من الضروري إنشاء كائن <code>PictureFileCallbacks</code> إذا أُعلن عن أسلوب دالة الاستدعاء بهذه الطريقة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class PictureFile &lt; ApplicationRecord
  after_destroy PictureFileCallbacks
end
</code></pre>

<p>
	يمكنك إعلان العدد الذي تريده من دوال الاستدعاء داخل أصناف دالة الاستدعاء.
</p>

<h2>
	<a id="10____303" rel=""></a>10- عمليات دوال الاستدعاء
</h2>

<p>
	يوجد دالتي استدعاء إضافيتين تعمل عند الانتهاء من عملية قاعدة البيانات: <code>after_commit</code> و <code>after_rollback</code>، وهما مشابهين لـ <code>after_save</code> إلا أنهم لا يعملون حتى يُنفّذ التغيير في قاعدة البيانات أو يتم التراجع عنه، وهما مفيدان للغاية عندما تحتاج نماذج <code>active record</code> إلى التفاعل مع الأنظمة الخارجية والتي هي ليست جزء من عملية قاعدة البيانات.<br>
	على سبيل المثال، فكر في المثال السابق حيث احتاج نموذج <code>PictureFile</code> إلى حذف ملف بعد تدمير السجل، إذا أُصدر استثناء بعد استدعاء دالة الاستدعاء <code>after_destroy</code> و أُرجعت العملية، فسيحذف الملف وسيبقى النموذج في حالة غير متناسقة، على سبيل المثال، افترض أن <code>picture_file_2</code> في الشيفرة البرمجية أدناه غير صحيح و أصدر أسلوب <code>save!</code> خطأََ:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>PictureFile.transaction do
  picture_file_1.destroy
  picture_file_2.save!
End
</code></pre>

<p>
	يمكننا تجنب هذه المشكلة باستخدام دالة الاستدعاء <code>after_commit</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class PictureFile &lt; ApplicationRecord
  after_commit :delete_picture_file_from_disk, on: :destroy
 
  def delete_picture_file_from_disk
    if File.exist?(filepath)
      File.delete(filepath)
   end
  end
end
</code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			يُحدد الخيار <code>:on</code> عند تشغيل الاستدعاء، وإذا لم تضعه، ستشتغل دالة الاستدعاء عند كل عمل.
		</p>
	</div>
</blockquote>

<p>
	بما أنه من الشائع استخدام <code>after_commit</code> عند الإنشاء والتحديث والحذف، فتوجد أسماء مستعارة aliases لهذه العمليات:
</p>

<ul>
<li>
		<code>after_create_commit</code>
	</li>
	<li>
		<code>after_update_commit</code>
	</li>
	<li>
		<code>after_destroy_commit</code>
	</li>
</ul>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9144_7" style="">
<code>class PictureFile &lt; ApplicationRecord
  after_destroy_commit :delete_picture_file_from_disk
 
  def delete_picture_file_from_disk
    if File.exist?(filepath)
      File.delete(filepath)
    end
  end
end
</code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تحذير:</strong><br>
			تُستدعى دوال الاستدعاء <code>after_commit</code> و<code>after_rollback</code> لجميع النماذج التي تنشئ، تُحدّث أو تُدمّر داخل كتلة العملية (transaction)، ومع ذلك، إذا أصدر استثناء داخل واحد من دوال الاستدعاء، فلن تنفذ بقية أساليب <code>after_commit</code> و <code>after_rollback</code> المتبقية، وعلى هذا النحو، إذا كانت شيفرة (code) دالة الاستدعاء تصدر استثناء، ستحتاج إلى التعامل معه داخل دالة الاستدعاء من أجل السماح بالعمل لبقية دوال الاستدعاء.
		</p>
	</div>
</blockquote>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/active_record_callbacks.html" rel="external nofollow">Ruby on Rails</a>
</p>
]]></description><guid isPermaLink="false">613</guid><pubDate>Sat, 03 Feb 2018 12:14:52 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642; Rails &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; AZK</title><link>https://academy.hsoub.com/programming/ruby/rails/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-rails-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-azk-r611/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_01/5a6e3d1aa895d_01(2).png.87ad34b7ac24135c4129849056de259e.png" /></p>

<h2 id="مقدمة">
	مقدمة
</h2>

<p>
	إنّ <a href="https://github.com/azukiapp/azk" rel="external nofollow">azk</a> عبارة عن أداة خفيفة مفتوحة المصدر، تستطيع استخدامها لتنسيق بيئات التطبيقات. هل سبق أن كان لديك تطبيق يعمل على محطة العمل المحليّة الخاصة بك، ووجدت أنّ الإعدادات تختلف كليًا عندما تقوم بنشر التطبيق على مخدّم إنّتاج. تُقدّم هذه المقالة أداة تنسيق، تُدعى azk، والتي يتم استخدامها حاليًا <a href="http://run.azk.io/" rel="external nofollow">من قبل هذه التطبيقات</a>، وهي قابلة للاستخدام لأكثر من ذلك بكثير. عندما تقوم بنشر تطبيق جاهز للعمل مع azk، فإنّه يمكنك بسهولة إنّ تشغلّه محليًا أو في مخدّم إنّتاج. لا يجعل azk تشغيل التطبيق فقط سهلًا و سريعًا بل كل تبعياته أيضًا، بما فيها نظام التشغيل المطلوب، اللغات، أطر العمل، قواعد البيانات و التبعيات الأخرى (المهام الثقيلة، الطويلة، التكرارية، الأكثر عرضة للخطأ)، سواء كنت تعمل في بيئة محلية أو على مخدم.<br>
	إنّ غرض هذه المقالة، هو إظهار كيف يعمل azk كأداة تنسيق، باستخدام تطبيق Rails بسيط يُدعى <a href="https://github.com/run-project/stringer" rel="external nofollow">Stringer</a> كمثال. يهتم azk بالعديد من التفاصيل خلف الكواليس، لجعل عملية التنسيق أسهل. لهذا، تحوي هذه المقالة على العديد من الخطوات الاختيارية، التي ليست بضرورية لإعداد التطبيق المثال، ولكنها تشرح آلية عمل azk. سوف نقوم بتشغيل التطبيق من شفرة المصدر على جهاز حاسوب محلي، ثم نشره على مخدّم، و من ثم سنقوم ببعض التغييرات المحليّة، وبعدها نقوم بنشر هذه التغييرات، و من ثم سنقوم بعميلة الإرجاع. بعد إتمام هذه المقالة، سوق تحصل على فكرة جيدة حول كيفية عمل azk كأداة تنسيق سير عملية التطوير والنشر الخاصة بك.
</p>

<h2 id="كيف-يعمل؟">
	كيف يعمل؟
</h2>

<p>
	بدايةً، يُنسق azk بيئة التطبيق على جهاز الحاسب المحلي الخاص بك. حالما يعمل التطبيق لديك محليًا، سيقوم azk أيضًا بتنسيق نشره إلى المخدّم Droplet الخاص بك. طالما يُشغل azk التطبيقات من شفرة المصدر، فإنّك تستطيع أن تعمل مع التطبيق محليًا (إذا كنت ترغب بذلك)، و من ثم تقوم بنشره أو استرجاعه مرة ثانية بدون أيّة خطوات إضافية خاصة. يعزل azk البيئات التي تستخدم الحاويات، ولهذا فمن الآمن تشغيل التطبيقات على جهاز الحاسب المحلي الخاص بك. يعمل azk مع كل من المشاريع الجديدة، تلك التي تبدأ منذ الصفر، أو مع الشيفرات الموجودة سابقًا.
</p>

<h2 id="استخدام-azk-مع-تطبيقات-مخصّصة">
	استخدام azk مع تطبيقات مخصّصة
</h2>

<p>
	باستخدام القائمة الحالية من <a href="http://run.azk.io/" rel="external nofollow">التطبيقات التي تم تشكيلها مسبقًا للعمل مع azk</a> كأمثلة، و مع قليل من العمل الإضافي ستستطيع إعداد أي مشروع للعمل مع azk. للقيام بهذا أضف الملف <a href="http://docs.azk.io/en/azkfilejs/" rel="external nofollow">Azkfile</a> إلى مشروعك.<br>
	Azkfile عبارة عن ملف رئيسي manifest، يحتوي العناصر الضرورية لتشغيل التطبيق، و يقوم بتلخيص علاقاتها فيما بينها (نظام التشغيل، اللغات، قواعد البيانات، … ).<br>
	فوائد إضافة الملف Azkfile إلى مشروعك:
</p>

<ul>
<li>
		استخدام azk لأتمته إعداد البيئة لمشروعك محليًا و عند النشر.
	</li>
	<li>
		يستطيع الأشخاص الأخرين، الذين يرغبون بنشر تطبيقك، القيام بهذا باستخدام azk.
	</li>
</ul>
<h2 id="المتطلبات-الأساسية">
	المتطلبات الأساسية
</h2>

<p>
	للمتابعة مع هذه المقالة، فإنّك ستحتاج إلى جهاز حاسوب يقوم بتشغيل أية من أنظمة التشغيل التالية(64 - بت) للبيئة المحليّة الخاصة بك:
</p>

<ul>
<li>
		Mac OS X 10.6 (Snow Leopard) أو أي إصدار لاحق.
	</li>
	<li>
		Ubuntu 12.04، 14.04 or 15.10
	</li>
	<li>
		Fedora 21 or 22
	</li>
</ul>
<p>
	أيضاً ستحتاج إلى إنّ تكون قادر على تشكيل git commits.
</p>

<ul>
<li>
		يحتاج جهاز حاسوبك إلى تثبيت Git. إنّظر إلى هذه السلسلة لاستخدام Git من أجل التعليمات الخاصة لأنظمة التشغيل Linux، أو قم بزيارة صفحة تحميل Git.
	</li>
	<li>
		تأكّد من قيامك بتشغيل الأوامر المقترحة :
	</li>
</ul>
<pre class="ipsCode" id="ips_uid_8397_9">
git config --global user.email "you@example.com"
git config --global user.name "Your Name"</pre>

<p>
	وذلك قبل القيام بقراءة المقالة، انظر الروابط السابقة للحصول على التفاصيل حول Git. لاحظ أنّه لا يوجد ضرورة للحصول على مخدّم فعّال Droplet في هذا الدرس. سيقوم azk بتشكيل واحد باستخدام واجهة التطبيق DigitalOcean’s <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>. يُكلف نشر مخدم Droplet المال، ومن أجل هذا الدرس ستقوم بنشر مخدم Droplet، يحوي افتراضيًا فقط واحد جيجابايت.
</p>

<p>
	<strong>مستخدمي Linux</strong> : تثبيت الـ Docker:<br>
	إذا كنت تستخدم نظام تشغيل ( Linux Ubuntu أو Fedora)، ستحتاج لتثبيت الـ <a href="https://www.docker.com/" rel="external nofollow">1.8.1 Docker</a> أو أي اصدار لاحق، وذلك لاستخدامه كبرمجية حاويّة. إنّ تشغيل سكريبت تثبيت Docker، هي إحدى طرق تثبيته. (بشكل عام، كُن متأكد من فهمك ماذا يفعل السكريبت، وذلك قبل القيام بتشغيله):
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code> $ wget -nv https://get.docker.com/ -O- -t 2 -T 10 | bash
</code></pre>

<p>
	إذا كنت ترغب بتعلّم المزيد حول تثبيت Docker في نظام التشغيل Linux، تفحّص <a href="https://docs.docker.com/engine/installation/" rel="external nofollow">تعليمات التثبيت</a> المتاحة في ملفات التوثيق الرسمية.<br><strong>مستخدمي Mac OS X</strong> : تثبيت الـ VirtualBox:<br>
	ستحتاج إلى <a href="https://www.virtualbox.org/" rel="external nofollow">VirtualBox 4.3.6</a> أو أي اصدار لاحق، وذلك لاستخدامه كبرمجيّة حاويّة. لتثبيت VirtualBox، <a href="https://www.virtualbox.org/wiki/Downloads" rel="external nofollow">حمّل رزمة تثبيت Virtualbox المناسبة</a> من صفحة التحميل الرسميّة.
</p>

<h3 id="الخطوة-الأولى-–-تثبيت-azk-محليًا">
	الخطوة الأولى: تثبيت azk محليًا
</h3>

<p>
	سنقوم بتثبيت azk، باستخدام سكريبت تثبيت المشروع. تأكد من فهمك ماذا يفعل أي سكريبت، قبل تنفيذه في نظامك. إذا كان لديك للتو نسخة قديمة مثبتة من azk، فإنّك تستطيع استخدام سكريبت التثبيت لتحديث الـ azk. وإلا قُم بتفحص إرشادات تثبيت الحزم لنظم التشغيل المدعومة.<br><strong>تثبيت azk على Linux:</strong><br>
	إذا كنت تستخدم نظام التشغيل (Linux Ubuntu أوFedora)، قُم بتشغيل هذا الأمر في الوحدة الطرفية، وذلك لتثبيت azk باستخدام سكريبت المشروع. نحن ننصح بتدقيق أي سكريبت قبل تشغيله على نظامك:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ wget -nv http://azk.io/install.sh -O- -t 2 -T 10 | bash
</code></pre>

<p>
	بعد إتمام التثبيت، قُم بتسجيل الخروج، ومن ثم تسجيل الدخول مرة أخرى، وذلك لجعل كل التعديلات فعّالة. يتجلى سبب تسجيل الخروج، في أنّه خلال عملية التثبيت، سيتم إضافة مستخدمك إلى مجموعة الـ docker. تُعد هذه الخطوة مطلوبة، وبذلك نستطيع استخدام الـ Docker بدون أن تكون المستخدم الأساسي (root). أي عليك الخروج من الجلسة الحالية، لتحصل على كل التعديلات المضافة. إذا كنت ترغب بتعلم المزيد حول <a href="https://docs.docker.com/v1.8/installation/ubuntulinux/#create-a-docker-group" rel="external nofollow">مجموعة الـ Docker</a>، فإنّك تستطيع تفحص التوثيق الرسمي لـ Docker.<br><strong>تثبيت azk على Mac OS X:</strong><br>
	قُم بتشغيل الأمر التالي في الوحدة الطرفية، وذلك لتثبيت azk باستخدام سكريبت المشروع. نحن ننصح بتدقيق أي سكريبت قبل تشغيله على نظامك:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ curl -<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">sSL</abbr> http://www.azk.io/install.sh | bash
</code></pre>

<h3 id="الخطوة-الثانية-–-التحقق-من-تثبيت-azk">
	الخطوة الثانية: التحقق من تثبيت azk
</h3>

<p>
	حالما يصبح تثبيت azk كامل، قُم بتشغيل الأمر الذي في الأسفل، وذلك للتحقق من نجاح عملية التثبيت:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk version
</code></pre>

<p>
	يتحقق هذا الأمر من نسخة الـ azk المثبّتة. إذا أعاد هذا الأمر رقم النسخة (على سبيل المثال azk 0.17.0 أو أي إصدار لاحق)، فالوضع جيد و تستطيع الانتقال إلى الخطوة التالية.<br>
	تهانينا لك على تثبيت azk في البيئة المحليّة الخاصة بك. إذا لم يكن الأمر كذلك، فاقرأ أدناه أحد أقسام تحرّي الأخطاء وإصلاحها للحصول على المساعدة.<br><strong>استكشاف الأخطاء وإصلاحها في عملية تثبيت azk في Linux:</strong><br>
	دعونا نتفحص نسخة الـ Docker المثبّتة، وذلك عن طريق تشغيل الأمر:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ docker version
</code></pre>

<p>
	ستحتاج إلى الإصدار 1.8.1 أو أحدث.<br>
	على كل حال، إذا حصلت على رسالة خطأ، فهذا يعني لم تحصل حتى الآن على تثبيت Docker، <a href="https://docs.docker.com/engine/installation/" rel="external nofollow">تتبع إرشادات التثبيت الخاصة</a> بنظام التشغيل في ملفات توثيق Docker.<br>
	بعد قيامك من التأكد من حصولك على النسخة المثبّتة المناسبة من Docker، قُم بتشغيل الأمر التالي كمستخدم sudo و ذلك للتأكد من أنّ مستخدمك في مجموعة docker:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ id -Gn
</code></pre>

<p>
	إذا كانت قائمة المجموعات تتضمن docker، هذا يعني أنه تم إعداده بشكل صحيح. و إلا، إذا لم تحصل على الكلمة docker في قائمة المجموعات، قُم بتشغيل هذا الأمر لإضافة مستخدمك إلى المجموعة:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ sudo usermod -aG docker $USER
</code></pre>

<p>
	ومن ثم قُم بتسجيل الخروج، و تسجل الدخول مرة أخرى. تحقق من الأمر <code>id –Gn</code> مرة أخرى للتأكد من أنّه يُعيد قائمة المجموعات مع كلمة docker بينهم. إذا كانت هذه الإرشادات غير كافية لجعل الـ Docker يعمل بالشكل المناسب (على سبيل المثال، لا تزال غير قادر على تشغيل أمر <code>docker version</code> بشكل صحيح)، يّرجى الرجوع إلى <a href="https://docs.docker.com/engine/installation/" rel="external nofollow">تعليمات تثبيت Docker</a>.<br><strong>استكشاف الأخطاء وإصلاحها في عملية تثبيت azk في Mac OS X:</strong><br>
	تأكّد من تثبيت VirtualBox
</p>

<pre class="ipsCode" id="ips_uid_8397_17">
$ which VBoxManage
</pre>

<p>
	إذا كان هذا يُعيد مسار ملف (مثل، <code>usr/local/bin/VboxManage</code>/)، فنستطيع المضي قُدمًا. و إلا، إذا كان يُعيد رسالة " not found "، هذا يعني ليس لديك تثبيت VirtualBox. في هذه الحالة، <a href="https://www.virtualbox.org/wiki/Downloads" rel="external nofollow">قُم بتحميل و تثبيت رزمة تثبيت VirtualBox</a> من الموقع الرسمي لهم.
</p>

<h3 id="اختيارية-الخطوة-الثالثة--التعلّم-حول-التطبيق-التجريبي-stringer">
	الخطوة الثالثة (اختيارية): التعلّم حول التطبيق التجريبي Stringer
</h3>

<p>
	لقد قُمنا باختيار Stringer كتطبيق تجريبي لهذه المقالة، وذلك لأنه تطبيق بسيط، وتم إعداده للعمل مع azk. وهو عبارة عن تطبيق Rails مع حالة استخدام محددة جيدًا: قارئ RSS أساسي.
</p>

<h3 id="المزيد-حول-stringer">
	المزيد حول Stringer
</h3>

<p>
	تُقدم بعض مواقع الأخبار أيضًا محتواها في صيغة تغذية RSS. هذه عبارة عن صيغة ملف XML قياسية، تُمكن الناشرين من نشر المعطيات بشكل اتوماتيكي. قارئ RSS هو عبارة عن برنامج مُستخدم للاشتراك، وتقديم محتوى الـ RSS. تُزيل عملية الاشتراك في تغذية RSS لموقع ما، حاجة المستخدمين للتفحص اليدوي للموقع للحصول على المحتوى الجديد. حيث يستطيع المستخدمين تشكيل قائمة بالتغذيات المُشترك فيها، وتخصيص محتواهم على قارئ RSS (عادةً على شكل قائمة مرتبة ترتيبًا زمنيًا)
</p>

<h3 id="اختيارية-الخطوة-الرابعة--إعداد-تطبيق-مُخصّص-لاستخدام-azk">
	الخطوة الرابعة (اختيارية): إعداد تطبيق مُخصّص لاستخدام azk
</h3>

<p>
	طالما أنّ التركيز الأساسي لهذه المقالة هو على إظهار كيفية عمل azk للتطبيقات، التي تملك للتو تفاصيل البيئة المنصوص عليها للعمل مع azk، فعلى المدى الطويل هذه الأداة، هي أكثر فائدة عندما يمكنك استخدامها لنشر أي تطبيق. لهذا، خُذ نظرة عن كيفية مقارنة <a href="https://github.com/run-project/stringer" rel="external nofollow">هذه النسخة من Stringer</a> مع <a href="https://github.com/swanson/stringer" rel="external nofollow">النسخة الأساسية من Stringer</a> في المستودع.<br>
	تملك نسخة azk فقط إضافتين اثنتين إلى نسخة Stringer الأصلية:
</p>

<ul>
<li>
		ملف Azkfile، الذي يزّود بمعلومات البيئة لـ azk
	</li>
	<li>
		زر azk لتشغيل المشروع Run Project
	</li>
</ul>
<p>
	يمكن تعلم المزيد حول جعل azk يعمل مع تطبيقات أخرى، وذلك عن طريق ملفات توثيق azk حول ملف <a href="http://docs.azk.io/en/azkfilejs/" rel="external nofollow">Azkfile</a> و زر تشغيل المشروع <a href="http://docs.azk.io/en/run-project-button/" rel="external nofollow">Run Project</a>. تالياً، سوف نرى كيف يبدو التطبيق الصديق لـ azk في GitHub.
</p>

<h3 id="اختيارية-الخطوة-الخامسة--استخدام-زر-تشغيل-المشروع-لـ-azk-على-github">
	الخطوة الخامسة (اختيارية): استخدام زر تشغيل المشروع لـ azk على GitHub
</h3>

<p>
	إنّ جزء الممارسات الأفضل من azk من أجل مشاريع GitHub، هو التوضيح الجيد لكيفيّة عمل هذا المشروع مع azk. لهذا، بدلاً من إظهار فقط أمر الـ azk في وسط ملف readme للمشروع، فإنّ المشروع الذي يستخدم azk يستطيع استخدام زر تشغيل المشروع، وذلك للعزل البصري لأمر الـ azk. يستخدم Stringer هذا الزر. قُم بزيارة قسم التشغيل المحلي لنسخة azk المتشعبة من Stringer. أضغط زر تشغيل المشروع Run Project.
</p>

<p style="text-align: center;">
	<img alt="001 (1).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26751" data-unique="k12d3uzgt" src="https://academy.hsoub.com/uploads/monthly_2018_01/5a6e3841d0330_001(1).png.a1a6106632efd63c789d78b0e9d26db0.png"></p>

<p>
	في أول مرة تضغط فيها زر تشغيل المشروع، سوف ترى شرح بسيط عن ماذا يجري. عندما تصبح جاهزا للمضي قُدماً، انقر على الزر OK، DISMISS في أسفل الشرح.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="26752" href="https://academy.hsoub.com/uploads/monthly_2018_01/5a6e3842eecbe_002(1).png.70b9b54da63fd1c47f22c03a4a326b3a.png" rel=""><img alt="002 (1).png" class="ipsImage ipsImage_thumbnailed" data-fileid="26752" data-unique="xanhdn3xf" src="https://academy.hsoub.com/uploads/monthly_2018_01/5a6e384521766_002(1).thumb.png.1848370e2f9cffe18853622e835e9cb1.png"></a>
</p>

<p>
	بعدها سيتم توجيهك إلى صفحة مع أمر azk لمشروع Stringer.
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk start -o run-project/stringer
</code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="26753" href="https://academy.hsoub.com/uploads/monthly_2018_01/003.png.4322e49d9d3f3265232387504c7c0dce.png" rel=""><img alt="003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26753" data-unique="8nme4sill" src="https://academy.hsoub.com/uploads/monthly_2018_01/003.thumb.png.3dc47376234fd8126455f231b37f7fd5.png"></a>
</p>

<p>
	<br>
	يمكنك دائماً أنّ تنقر على إشارة ما هذا؟ على الزاوية العليا اليُمنى، وذلك لترى الشرح مرّة أخرى. في مركز الشاشة، يوجد صندوق أوامر مع ثلاث علامات تبويب: curl، wget، azk. طالما لدينا للتو مُثبت azk فتستطيع استخدام علامة التبويب azk. هذا هو الأمر، الذي سنستخدمه في الخطوة التالية للتشغيل الفعلي لـ Stringer.
</p>

<h3 id="الخطوة-السادسة--تشغيل-stringer-محليًا">
	الخطوة السادسة: تشغيل Stringer محليًا
</h3>

<p>
	في هذا القسم سنستخدم azk لتشغيل Stringer على محطّة العمل المحليّة. دعونا نتأكد أنّنا في المسار الرئيسي home على جهاز حاسوبنا المحلي (إذا قمت باستخدام مجلد تثبيت مختلف، تذكر فقط تغيير الأوامر إلى مسارك المختار):
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ cd ~
</code></pre>

<p>
	أمضي قُدمًا، و قم بتشغيل الأمر التالي على حاسوبك المحلي، وذلك لتشغيل Stringer:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk start -o run-project/stringer
</code></pre>

<p>
	طالما هذه هي أول مره تقوم بها بتشغيل azk، سيطلب منك قبول بنود الخدمة. و يجب أنّ تظهر رسالة كالتالية:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>? =========================================================================
 Thank you for using azk! Welcome!
 Before we start، we need to ask: do you accept our Terms of Use?
 http://docs.azk.io/en/terms-of-use
 =========================================================================
 (Y/n)
</code></pre>

<p>
	اضغط على Y إذا كنت موافق أو N إذا كنت غير موافق. و من ثم اضغط على ENTER لتأكيد جوابك. في حالة عدم موافقتك، فلن تتمكن من استخدام azk. و اخيراً، سيقوم azk أوتوماتيكيًا بتحميل الشفرة المصدر لـ Stringer، إضافة إلى أنّ الملف المسند Azkfile سيقوم بتشغيل هذا الشفرة في بيئة معزولة و آمنة في حاسوبك المحلي. ومن ثم سيتم سؤالك فيما إذا كنت ترغب ببداية تشغيل عميل الـ azk.
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>? The agent is not running، would you like to start it? (Y/n)
</code></pre>

<p>
	العميل هو عبارة عن مُركب azk، الذي يقوم بإعداد Docker (على نظام التشغيل Linux )، أو بإعداد الآلة الافتراضيّة VirtualBox (على نظام التشغيل Mac OS X). اضغط <code>ENTER</code> للجواب “Yes” (الخيار الافتراضي). في أول مرة تُشغل فيها العميل، سيقوم azk بتشغيل إعداداته. يقوم الإعداد بالعديد من الأشياء وراء الكواليس، بما في ذلك توليد الملف <code>/etc/resolver/dev.azk.io</code>، الذي يحوي إعدادات نظام أسماء النطاقات DNS، لتصميم العناوين التي تنتهي باللاحقة <code>dev.azk.io</code>. يستخدم azk هذه اللاحقة عند تشغيل التطبيقات لاستخدام العناوين القابلة للقراءة بدلاً من الاستخدام اليدوي للعناوين من الشكل <a href="http://localhost" rel="external nofollow">http://localhost</a>:PORT_NUMBER . أيضاً هذا يقوم بتجنب تعارض أرقام المنافذ بين التطبيقات المختلفة. بشكل أساسي يقوم هذا بنفس الشيء عند تحرير ملفك <code>/etc/hosts</code> لإعادة توجيه اسم نطاق محليًا.<br>
	إذا حصلت على رسالة من الشكل التالي:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>? Enter the vm ip: (192.168.50.4)
</code></pre>

<p>
	فإنّك تستطيع إدخال أي عنون IP محلي، ترغب بتشغيل التطبيق عليه. يجب أن تكون الحالة الافتراضية مناسبة لجميع الحالات. للموافقة على هذا، فقط اضغط ENTER. لإتمام إعدادات عميل الـ azk، سيتم سؤالك عن كلمة المرور الخاصة بالمستخدم sudo (لمستخدمي نظام التشغيل Mac OS X، هي عبارة عن كلمة مرور المُشرف admin). الآن سيبدأ azk بالعمل. سوف ترى أنّ azk يُحمّل العناصر المُسردة في الملف Azkfile (على صيغة صور Docker ). من الممكن أن يستغرق تحميل هذه الصور أول مرة عدة دقائق (حوالي 10 دقائق أو أقل).<br>
	حالما يُكمل azk الإعداد، سيقوم مُتصفحك بشكل أتوماتيكي بتحميل شاشة البدء لـ Stringer على حاسوبك المحلي.
</p>

<p style="text-align: center;">
	<img alt="004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26754" data-unique="kcjff88y8" src="https://academy.hsoub.com/uploads/monthly_2018_01/004.png.aa37aa320b47a87ad57f3a574ae8a2ea.png"></p>

<p style="text-align: center;">
	<img alt="005.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26755" data-unique="pfkp8rm4h" src="https://academy.hsoub.com/uploads/monthly_2018_01/005.png.c65e85f0dc8c5870ea1168d304f8162a.png"></p>

<p>
	كما تستطيع إنّ ترى، أنّه يستخدم اسم نطاق محلي DNS، و هذا التطبيق مرئي على <a href="http://stringer.dev.azk.io" rel="external nofollow">http://stringer.dev.azk.io</a>. و تستطيع الوصول إلى التطبيق بشكل يدوي عبر الذهاب إلى <a href="http://stringer.dev.azk.io" rel="external nofollow">http://stringer.dev.azk.io</a> . إذا كنت ترغب بإعداد كلمة المرور و بداية التشغيل باستخدام التطبيق، فإنّك تستطيع فعل ذلك. نحن نرغب فقط برؤية أنّ azk يستطيع تشغيل Stringer محلياً. والآن طالما لديك Stringer يعمل على الحاسوب المحلي، فتستطيع نشره من جهاز الحاسوب لديك إلى المخدّم Droplet.
</p>

<h3 id="الخطوة-السابعة--الحصول-على-الرمز-digitalocean-api-token">
	الخطوة السابعة: الحصول على الرمز DigitalOcean <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> Token
</h3>

<p>
	قبل أن نتمكن من نشر Droplet من azk، فإنّنا نحتاج إلى رمز <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> token. يُعطي هذا الرمز الإذن لـ azk لنشر مخدّم جديد على حسابك. في أول مرّة تقوم بها بتشغيل azk من هذه البيئة باستخدام هذا الرمز، سيتم نشر واحد جيجابايت مخدّم جديد Ubuntu 14.04 Droplet . و ستستخدم عمليات النشر اللاحقة من نفس البيئة المحليّة، نفس المخدّم المفرد Droplet. اتّبع الإرشادات من قسم المراجع المرتبطة بالمقالة حول <a href="https://www.digitalocean.com/community/tutorials/how-to-use-the-digitalocean-api-v2#how-to-generate-a-personal-access-token" rel="external nofollow">كيفية تشكيل رمز الوصول الشخصي</a>. و يجب أن يمتلك الرمز المُشكّل تصاريح الكتابة القراءة. قُم بنسخ المحارف الأربعة و الستين بالترميز الست عشري لرمزك، بشكل مشابه للتالي:
</p>

<p style="text-align: left;">
	<strong>Example <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> Token</strong>
</p>

<pre class="ipsCode" id="ips_uid_8397_19">
A17d6a72566200ad1a8f4e090209fe1841d77d7c85223f769e8c5de47475a726
</pre>

<p>
	سوف ترى هذا الرمز النصيّ فقط مرة واحدة، لذلك قُم بنسخه إلى مكان آمن. (تذكّر، إذا تم اختراق هذا الرمز، فإنّه يمكن استخدامه للدخول إلى حسابك، لذلك حافظ عليه خاصًا). من أجل الإرشادات أسفلا، تذكر استبدال الرمز المثال بالرمز الحقيقي الخاص بك.<br>
	اذهب إلى مجلد Stringer:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ cd ~/stringer
</code></pre>

<p>
	احفظ رمز الوصول الشخصي في ملف ستدعوه <code>env.</code> للقيام بهذا، قُم بتشغيل أمر تشكيل ملف (لا تنسى استبدال الرمز):
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ echo "DEPLOY_API_TOKEN=a17d6a72566200ad1a8f4e090209fe1841d77d7c85223f769e8c5de47475a726" &gt;&gt; .env
</code></pre>

<p>
	يجب إنّ يبدو محتوى الملف <code>env.</code> بالشكل التالي:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>DEPLOY_API_TOKEN=a17d6a72566200ad1a8f4e090209fe1841d77d7c85223f769e8c5de47475a726
</code></pre>

<h3 id="اختياريه-الخطوة-الثامنة--التعلم-حول-مفاتيح-ssh">
	الخطوة الثامنة (اختيارية): التعلم حول مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>
</h3>

<p>
	ليس عليك إنّ تقوم بأي شيء لإعداد مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> من أجل azk، ولكن من المفيد معرفة الكيفية التي يستخدم فيها azk هذا المفتاح. يستخدم azk مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> للوصول إلى المخدّم Droplet. إذا كان لديك للتو مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>، فإنّ azk سيستخدمه. لرؤية فيما إذا كان لديك مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> على جهاز الحاسوب لديك، شغّل:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ ls ~/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/*.pub
</code></pre>

<p>
	إذا قام بإرجاع رسالة “not found”، فهذا يعني إنّه ليس لديك أيّة مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> على جهاز الحاسوب. في هذه الحالة، سيولّد azk بشكل أتوماتيكي مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> جديد، ليتم استخدامه حصريًا لنشر أي تطبيق جديد من جهاز الحاسوب لديك. سيقوم azk بتوليد مفتاحه في الذاكرة المحجوزة له، ولن يقوم بأيّة تعديلات على مسارك ~/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>.<br>
	إذا كنت ترغب بتفحص المفتاح العام المولّد، يمكنك تشغيل الأمر التالي بعد نشر التطبيق الأول:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk deploy shell -c "cat /azk/deploy/.config/<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/*.pub"
</code></pre>

<h3 id="الخطوة-التاسعة--النشر-مع-azk">
	الخطوة التاسعة: النشر مع azk
</h3>

<p>
	بشكل افتراضي، سيولد azk مخدّم DigitalOcean Droplet واحد جيجابايت، يُشغّل النظام Ubuntu 14.04، وذلك من أجل نشر تطبيقك. إذا كنت ترغب بنشر Droplet بمواصفات مختلفة، فيمكنك تغيير الإعدادات في خصائص <code>envs</code> لنظام <code>deploy</code> في الملف <code>Azkfile.js</code> . من أجل الإرشادات الإضافية أشر إلى <a href="http://docs.azk.io/en/deploy/#supported-customization" rel="external nofollow">ملفات توثيق حول نشر azk</a> .
</p>

<p>
	أولاً، اذهب إلى مسار Stringer ( أو إلى مسار تطبيقك):
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ cd ~/stringer
</code></pre>

<p>
	ومن ثم، ابدأ عملية النشر، فقط قُم بتشغيل:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk deploy
</code></pre>

<p>
	إنّ الأمر <code>azk deploy</code>، هو الأمر الذي ستقوم بتشغيله معظم الأوقات، عندما تستخدم azk لتنسيق تطبيقك. من الممكن أن تستغرق أول عملية نشر فترة معينة (حوالي عشر دقائق)، حتى يقوم azk بكل العمل. بشكل مخصص، على azk القيام بما يلي:
</p>

<ul>
<li>
		تحميل عناصر الدعم ( صورة Docker للنشر)
	</li>
	<li>
		تشكيل و إعداد الـ Droplet
	</li>
	<li>
		رفع شفرة المصدر للتطبيق إلى المخدّم Droplet
	</li>
	<li>
		تشغيل التطبيق
	</li>
</ul>
<p>
	بعدها ستستغرق كل عملية نشر جديده لهذا التطبيق من جهاز الحاسوب لديك مدة زمنية قليلة (حوالي 30 ثانية أو أقل)، هذا لان معظم الخطوات الطويلة جاهزة للتو. إذا كان مفتاحك <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> محمي بكلمة مرور، فسيكون مطلوباً وقت أكبر لعملية النشر. فقط قُم بكتابة كلمة المرور للمفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>، و أضغط زر <code>ENTER</code> في كل مرة تظهر رسالة كالتالية:
</p>

<p style="text-align: left;">
	<strong>Output</strong>
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>Enter passphrase for ~/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/id_rsa:
</code></pre>

<p>
	سيظهر خرج الوحدة الطرفية بعض الإجراءات المُتخذة على النظام البعيد، تنتهي برسالة النشر الناجحة <code>App successfully deployed at http://your_server_ip</code>.
</p>

<p style="text-align: center;">
	<img alt="006.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26756" data-unique="589p1ss3f" src="https://academy.hsoub.com/uploads/monthly_2018_01/006.png.db6652d77a2e04e276c12dd2ce4daabd.png"></p>

<p>
	قُم بزيارة الموقع http://your_server_ip لعرض التطبيق المُستضاف على الخادم الخاص بك.
</p>

<p style="text-align: center;">
	<img alt="007.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26757" data-unique="fpwz2f0n7" src="https://academy.hsoub.com/uploads/monthly_2018_01/007.png.2f308c1f76afff8fc99bcb187fa369f2.png"></p>

<p>
	من الآن، يُمكنك تغيير شفرة التطبيق على جهاز الحاسوب الخاص بك، و يمكنك اختباره محلياً، و يمكنك نشر التغييرات على المخدّم Droplet بواسطة الأمر <code>azk deploy</code>.
</p>

<h3 id="الخطوة-العاشرة--تعديل-stringer">
	الخطوة العاشرة: تعديل Stringer
</h3>

<p>
	لتوضيح سهولة استخدام azk لنشر تطبيق، للتخصيص، أو للتحكم في النسخة، دعونا نقوم بعدد من التغييرات على صفحة الاشتراك Stringer، و من ثم نقوم بإعادة نشر التطبيق. تأكد من كونك على مسار Stringer:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ cd ~/stringer
</code></pre>

<p>
	دعونا نقوم بتعديل الملف <code>app/views/first_run/password.erb</code>، الذي هو عبارة عن الصفحة الحاوية على النص لصفحة الاشتراك الأولى.<br>
	استخدم <code>nano</code> أو محرر النصوص المفضل لديك:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ nano ~/stringer/app/views/first_run/password.erb
</code></pre>

<p>
	هنا نقوم بإضافة السطر الإضافي، الذي يقول "! It’s easy with azk ":
</p>

<p style="text-align: left;">
	<code>app/views/first_run/password.erb</code>
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>&lt;div class="setup" id="password-setup"&gt;
 &lt;h1&gt;&lt;%= t('first_run.password.title') %&gt; &lt;span class="orange"&gt; &lt;%= t('first_run.password.anti_social') %&gt;&lt;/span&gt;.&lt;/h1&gt;
 &lt;h2&gt;&lt;%= t('first_run.password.subtitle') %&gt;&lt;/h2&gt;
 &lt;h2&gt;It's easy with azk!&lt;/h2&gt;
 &lt;hr /&gt;
 . . .
&lt;/div&gt;
</code></pre>

<p>
	قُم بالحفظ و الخروج من محرر النصوص. إذا كنت تستخدم <code>nano</code>، اضغط <code>CTRL+O</code> للحفظ، و <code>CTRL+X</code> للخروج.<br>
	طالما إنّ Stringer مُعد افتراضياً للعمل في وضع الانتاج، لذلك فإنّ إعادة تحديث صفحة المتصفح ليس بكافٍ لتشغيل التغييرات. بل قُم بإعادة تشغيل التطبيق من azk:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk restart stringer -o
</code></pre>

<p>
	يجب على علامة التبويب الجديدة للمتصفح أن تفتح النسخة الجديدة من Stringer. أسفل النص الافتراضي مباشرةً “There is only one user: you”، يجب الآن أن يكتب “!It’s easy with azk”.
</p>

<h3 id="الخطوة-الحادية-عشر--إعادة-نشر-stringer">
	الخطوة الحادية عشر: إعادة نشر Stringer
</h3>

<p>
	الآن، دعونا نُودع (commit) التغييرات داخل نسخة نظام التحكم، من أجل أن نستطيع نشرها.
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ git add app/views/first_run/password.erb
$ git commit .
</code></pre>

<p>
	سيظهر لك محرر نصوص (على الأرجح nano أو vim). أدخل رسالة إيداع commit، مثل It is easy with azk. سيتم استخدام هذه الرسالة commit لتسمية الإصدارات من تطبيقك داخل azk، لذلك اختر الرسالة التي من شأنها تحفيز ذاكرتك، إذا كنت بحاجة إلى الرجوع إليها في وقت لاحق. احفظ و أغلق رسالة الـ commit.<br>
	إذا حصلت على الخطأ :
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code> fatal: empty ident name (for &lt;sammy@azk.(none)&gt;) not allowed 
</code></pre>

<p>
	عندها قُم بتشغيل أوامر الإعدادات المقترحة من أجل Git لإعداد عنوان إيميل و اسم (المزيد من التفاصيل في قسم المتطلبات الأساسية).
</p>

<p>
	لنشر تغييراتك و رفع تشغيل التطبيق على Droplet، قُم بتشغيل:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk deploy
</code></pre>

<p>
	بعد الانتهاء من ذلك، قُم بالوصول إلى عنوان IP لـ Droplet من متصفحك (مثلاً http://your_server_ip) .عندها يجب أن ترى أيضاً هنا السطر الجديد !It’s easy with azk
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="26758" href="https://academy.hsoub.com/uploads/monthly_2018_01/008.png.af236cad21092ac41b5c26252cfd5009.png" rel=""><img alt="008.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26758" data-unique="yd3axn44r" src="https://academy.hsoub.com/uploads/monthly_2018_01/008.thumb.png.d330652bdc90a1c3ecb7229530cdb7e0.png"></a>
</p>

<p>
	سيقوم هذا النشر الجديد بتشكيل نسخة جديدة من التطبيق على Droplet. إنّ كل نسخ التطبيق مخزنة، لذلك يمكنك العودة إلى نسخة سابقة ومن ثم إلى الأمام مرّة أخرى.
</p>

<h3 id="الخطوة-الثانية-عشر--الرجوع-إلى-خطوة-سابقة">
	الخطوة الثانية عشر: الرجوع إلى خطوة سابقة
</h3>

<p>
	للحصول على كل النسخ المتاحة من تطبيقنا على Droplet، شغّل الأمر التالي محليًا:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk deploy versions
</code></pre>

<p>
	يجب إنّ تكون النتيجة بقائمة من الشكل:
</p>

<p style="text-align: left;">
	<strong>Output</strong>
</p>

<pre class="ipsCode" id="ips_uid_8397_21">
⇲ Retrieving deployed versions...

 ➜ v2   It is easy with azk
    v1   Merge branch 'master' of https://github.com/swanson/stringer
</pre>

<p>
	لإرجاع التطبيق إلى نسخة أقدم، فقط قوم بتشغيل:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk deploy rollback v1
</code></pre>

<p>
	إنّ المعامل <code>v1</code> عبارة عن رقم النسخة، الذي يظهر على خرج الأمر <code>azk deploy versions</code>. إذا قمت بتشغيل الأمر بدون هذا المعامل (مثلاً، . <code>azk deploy rollback</code> )، سيرجع عندها التطبيق إلى نسخة سابقة تماماً قبل النسخة الحالية. لتفحص إتمام عملية الرجوع، فقط قُم بتحديث علامة تبويب المتصفح، التي تظهر نسخة المخدم. الآن عليك إنّ ترى التطبيق بدون النص الذي قمنا بإدخاله، أي يجب أن ترى النسخة الأصليّة من التطبيق. وإذا كنت ترغب بالرجوع للأمام، يمكنك اختيار النسخة الأحدث:
</p>

<pre class="ipsCode" id="ips_uid_8397_9">
<code>$ azk deploy rollback v2
</code></pre>

<p>
	أتت التسمية لهذه النسخ من رسائل الـ <code>git commit</code> في الخطوة السابقة.
</p>

<h2 id="الخاتمة">
	الخاتمة
</h2>

<p>
	في هذا الدليل التعليمي، لقد استخدمنا تطبيق Rails بسيط، لتوضيح كيف يقوم azk بأتمتة مهام إعداد بيئة تطبيقنا. يجعل هذا من السهل نشر التطبيق نفسه في عدة بيئات. إذا أعجبت بعملية النشر من azk، خُذ بعين الاعتبار استخدامه لمشروعك الخاص، أو إضافة الملف Azkfile إلى fork مشروع أخر مفتوح المصدر.<br>
	يدعم azk بالإضافة إلى عملية rollback و versions، غيرها من الأوامر الفرعيّة المساعدة، التي تسمح لنا بإنّجاز بعض الإجرائيات الإضافية (مثلاً، الوصول إلى Droplet’s shell عن طريق المفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> ).
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-azk" rel="external nofollow">How To Deploy a Rails App with azk</a> لصاحبه Felipe Arenales
</p>
]]></description><guid isPermaLink="false">611</guid><pubDate>Thu, 01 Feb 2018 10:06:00 +0000</pubDate></item><item><title>Active Record Validations: &#x627;&#x644;&#x62A;&#x62D;&#x642;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x62E;&#x635;&#x635;&#x629; &#x648;&#x627;&#x644;&#x623;&#x62E;&#x637;&#x627;&#x621;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-%D9%88%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-r591/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_12/02-2.png.a72db625f5b7a0213b5fe43f5c27b909.png" /></p>

<p>
	في الدرسين السابقين ألقينا <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-r573/" rel="">نظرة عامة حول التحقيقات</a> في Active Record وتعرّفنا على <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D9%85%D8%B3%D8%A7%D8%B9%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D8%A7%D8%AA-r576/" rel="">مساعدات التحقيقات</a> وتعرّفنا أيضًا على <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%88%D8%AE%D9%8A%D8%A7%D8%B1%D8%A7%D8%AA%D9%87%D8%A7-%D8%A7%D9%84%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-r579/" rel="">الخيارات الشائعة وأنواع التحقيقات</a> وسنتابع في هذا الدرس ما تبقى من هذا <a href="https://academy.hsoub.com/tags/ruby%20on%20rails%20103/" rel="">الدليل التعليمي</a> .
</p>

<h2 id="6-أداءتنفيذ-تحقيقات-مخصصة-performing-custom-validations">
	6 أداء/تنفيذ تحقيقات مخصّصة Performing Custom Validations
</h2>

<p>
	عندما لا تكون التحقيقات المدمجة كافية لاحتياجاتك يمكنك كتابة محققاتك الخاصّة أو وسائل تحقيق كما تفضّل.
</p>

<h3 id="61-المحققات-المخصصة-custom-validators">
	6.1 المحققات المخصّصة Custom Validators
</h3>

<p>
	المحققات المخصصة عبارة عن فئات تقتبس من <code>ActiveModel::Validator</code>. تلك الأصناف يجب أن تنفّذ وسيلة <code>validate</code> التي تأخذ سجل كـتعبير و تُؤدّي التحقيق عليه. يُستدعى المحقق الخاص باستخدام وسيلة <code>validates_with</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">MyValidator</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ActiveModel</span><span class="pun">::</span><span class="typ">Validator</span><span class="pln">
  </span><span class="kwd">def</span><span class="pln"> validate</span><span class="pun">(</span><span class="pln">record</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">unless</span><span class="pln"> record</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">starts_with</span><span class="pun">?</span><span class="pln"> </span><span class="str">'X'</span><span class="pln">
      record</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[:</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">'Need a name starting with X please!'</span><span class="pln">
    </span><span class="kwd">end</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln">
  include </span><span class="typ">ActiveModel</span><span class="pun">::</span><span class="typ">Validations</span><span class="pln">
  validates_with </span><span class="typ">MyValidator</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	أسهل طريقة لإضافة محققات مخصّصة للتحقق من خصائص شخصيّة تكون ب <code>ActiveModel::EachValidator</code> مناسب. في هذه الحالة يجب أن ينفّذ المتحقق الخاص وسيلة <code>validate_each</code> ، التي تأخذ ثلاثة تعبيرات: سجل و خاصّية و قيمة. يتم إدارتهم مع ما يناسبهم: الخاصّية يتم التحقق منها ، و قيمة الخاصّية يتم تجاوزها.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">EmailValidator</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveModel</span><span class="pun">::</span><span class="typ">EachValidator</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">validate_each</span><span class="pun">(</span><span class="pln">record</span><span class="pun">,</span><span class="pln"> attribute</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">unless</span></span><span class="pln"> value </span><span class="pun">=~</span><span class="pln"> </span><span class="hljs-regexp"><span class="pun">/</span><span class="pln">\A</span><span class="pun">([^@</span><span class="pln">\s</span><span class="pun">]+)@((?:[-</span><span class="pln">a</span><span class="pun">-</span><span class="pln">z0</span><span class="pun">-</span><span class="lit">9</span><span class="pun">]+</span><span class="pln">\.</span><span class="pun">)+[</span><span class="pln">a</span><span class="pun">-</span><span class="pln">z</span><span class="pun">]{</span><span class="lit">2</span><span class="pun">,})</span><span class="pln">\z</span><span class="pun">/</span><span class="pln">i</span></span><span class="pln">
      record</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="pln">attribute</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">options</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">message</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="hljs-string"><span class="str">"is not an email"</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">email</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	كما هو موضّح بالمثال يمكن دمج(ربط) محقّقات أساسيّة بمحقّقاتك الخاصّة.
</p>

<h3 id="62-الوسائل-المخصصة">
	6.2 الوسائل المخصّصة
</h3>

<p>
	يمكنك أيضًا إنشاء وسائل تؤكّد على حالة النموذج و تضيف رسائل إلى الـ <code>errorscollection</code> عندما يكونوا غير صالحين. يجب أن تسجّل بعد ذلك تلك الوسائل باستخدام فئة (validate (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr> ، مرورًا بالرموز الخاصة بأسماء وسائل التحقيق. يمكنك تمرير(إرسال) أكثر من رمز واحد لكل وسيلة لفئة و سيجري التحقيقات المخصصة في نفس الترتيب الذي سُجّلوا به. وسيلة <code>?valid</code> سوف تؤكّد أن مجموعة الأخطاء فارغة، لذلك يجب أن تضيف تحقيقاتك المخصّصة أخطاء إليها عندما ترغب أن يفشل التحقيق.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Invoice</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validate </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">expiration_date_cannot_be_in_the_past</span></span><span class="pun">,</span><span class="pln">
    </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">discount_cannot_be_greater_than_total_value</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">expiration_date_cannot_be_in_the_past
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> expiration_date</span><span class="pun">.</span><span class="pln">present</span><span class="pun">?</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> expiration_date </span><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Date</span></span><span class="pun">.</span><span class="pln">today
      errors</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">expiration_date</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"can't be in the past"</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">discount_cannot_be_greater_than_total_value
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> discount </span><span class="pun">&gt;</span><span class="pln"> total_value
      errors</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">discount</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"can't be greater than total value"</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	كما هي مضبُوطة افتراضيّا ، سوف تعمل هذه التحقيقات كل مرّة تستدعي <code>?valid</code> أو تحفظ الكائن. لكن من الممكن أيضًا التحكم في وقت عمل هذه التحقيقات بإعطاء خيار <code>on:</code> إلى وسيلة <code>validate</code> إما بـ <code>create:</code> أو <code>update:</code>
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Invoice</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validate </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">active_customer</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">on</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">create</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">active_customer
    errors</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">customer_id</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"is not active"</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">unless</span></span><span class="pln"> customer</span><span class="pun">.</span><span class="pln">active</span><span class="pun">?</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></code></pre>

<h2 id="7-التعامل-مع-أخطاء-التحقيق-working-with-validation-errors">
	7 التعامل مع أخطاء التحقيق Working with Validation Errors
</h2>

<p>
	بالإضافة إلى وسائل <code>?valid</code> و <code>?invalid</code> التي تم شرحها مُسبقًا ، يدعم Rails عددًا من الوسائل للتعامل مع مجموعة الأخطاء و يحقق في صحّة الكائن.
</p>

<h3 id="71-الأخطاء-errors">
	7.1 الأخطاء Errors
</h3>

<p>
	ترجع فئة <code>ActiveModel::Errors</code> يحتوي على كل الأخطاء. كل مفتاح هو اسم الخاصّية و القيمة في مجموعة مصفوفة من المتسلسلات النصّية بالأخطاء.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs avrasm"><span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> presence</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> length</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> minimum</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">new</span></span><span class="pln">
person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">valid</span></span><span class="pun">?</span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com"># =&gt; false</span></span><span class="pln">
person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">errors</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">messages</span></span><span class="pln">
 </span><span class="hljs-preprocessor"><span class="com"># =&gt; {:name=&gt;["can't be blank", "is too short (minimum is 3 characters)"]}</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">new</span></span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"John Doe"</span></span><span class="pun">)</span><span class="pln">
person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">valid</span></span><span class="pun">?</span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com"># =&gt; true</span></span><span class="pln">
person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">errors</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">messages</span></span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com"># =&gt; {}</span></span></code></code></pre>

<h3 id="72-الأخطاء-errors">
	7.2 الأخطاء [ ] Errors
</h3>

<p>
	تستخدم errors عندما تريد أن تفحص رسالة الخطأ لخاصّية معيّنة. تقوم بالرد بمجموعة مصفوفة من المتسلسلات النصّية بكل رسائل الأخطاء لخاصّية مُعيّنة ، كل متسلسلة برسالة خطأ واحدة. لو لم يكن هناك أخطاء مرتبطة بالخاصّية ، تقوم بالرد بمصفوفة فارغة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">length</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">minimum</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"John Doe"</span></span><span class="pun">)</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; true</span></span><span class="pln">
person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; []</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"JD"</span></span><span class="pun">)</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; false</span></span><span class="pln">
person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; ["is too short (minimum is 3 characters)"]</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; false</span></span><span class="pln">
person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln">
 </span><span class="hljs-comment"><span class="com"># =&gt; ["can't be blank", "is too short (minimum is 3 characters)"]</span></span></code></code></pre>

<h3 id="73-إضافة-الأخطاء-errorsadd">
	7.3 إضافة الأخطاء errors.add
</h3>

<p>
	تجعلك وسيلة <code>add</code> أن تضيف رسالة خطأ مرتبطة بخاصّية مُعيّنة. تقوم بأخذ الخاصّية و رسالة الخطأ كتعابير. ترد وسيلة <code>errors.full_messages</code> (أو مكافئاتها <code>errors.to_a</code> ) برسالة الخطأ بشكل مفضّل للمستخدم ، و اسم الخاصّية مكبّرًا ومضافًا على بداية كل رسالة ، كما يظهر في الأمثلة بالأسفل.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">a_method_used_for_validation_purposes
    errors</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"cannot contain the characters !@#%*()_-+="</span></span><span class="pun">)</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"!@#"</span></span><span class="pun">)</span><span class="pln">

person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln">
 </span><span class="hljs-comment"><span class="com"># =&gt; ["cannot contain the characters !@#%*()_-+="]</span></span><span class="pln">

person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">full_messages
 </span><span class="hljs-comment"><span class="com"># =&gt; ["Name cannot contain the characters !@#%*()_-+="]</span></span></code></code></pre>

<p>
	أن ترفق رسالة في بداية مصفوفة <code>errors.messages</code> لخاصّية ما ، مكافىء لأن تستخدم <code>errors#add</code> .
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">a_method_used_for_validation_purposes
    errors</span><span class="pun">.</span><span class="pln">messages</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="hljs-string"><span class="str">"cannot contain the characters !@#%*()_-+="</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"!@#"</span></span><span class="pun">)</span><span class="pln">

person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln">
 </span><span class="hljs-comment"><span class="com"># =&gt; ["cannot contain the characters !@#%*()_-+="]</span></span><span class="pln">

person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">to_a
 </span><span class="hljs-comment"><span class="com"># =&gt; ["Name cannot contain the characters !@#%*()_-+="]</span></span></code></code></pre>

<h3 id="74-تفاصيل-الأخطاء-errorsdetails">
	7.4 تفاصيل الأخطاء errors.details
</h3>

<p>
	يمكنك تحديد نوع محقّق جدول تقطيع تفاصيل الخطأ المُعاد التقطيع باستخدام وسيلة <code>errors.add</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">a_method_used_for_validation_purposes
    errors</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">invalid_characters</span></span><span class="pun">)</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"!@#"</span></span><span class="pun">)</span><span class="pln">

person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">details</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln">
</span><span class="hljs-comment"><span class="com"># =&gt; [{error: :invalid_characters}]</span></span></code></code></pre>

<p>
	لكي تحسّن تفاصيل الأخطاء ، لتحتوي مجموعة الحروف غير المسموح بها على سبيل المثال ، يمكنك تمرير مفاتيح إضافيّة إلى <code>errors.add</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">a_method_used_for_validation_purposes
    errors</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">invalid_characters</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">not_allowed</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"!@#%*()_-+="</span></span><span class="pun">)</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"!@#"</span></span><span class="pun">)</span><span class="pln">

person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">details</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln">
</span><span class="hljs-comment"><span class="com"># =&gt; [{error: :invalid_characters, not_allowed: "!@#%*()_-+="}]</span></span></code></code></pre>

<p>
	كل محقّقات Rails المدمجة تزيد جدول تقطيع التفاصيل بنوع محقّق متناظر.
</p>

<h3>
	7.5 قاعدة الأخطاء[ errors [ :base
</h3>

<p>
	يمكنك إضافة رسائلك أخطاء مرتبطة بحالة الكائن ككل بدلًا من كونها مرتبطة بخاصّية مُعيّنة. يمكنك أيضًا استخدام تلك الوسيلة عندما تريد أن تقول أن الكائن غير صالح للاستخدام ، بغض النظر عن قيم خصائصه. بما أن <code>[errors[ :base</code> مصفوفة ، يمكنك ببساطة إضافة متسلسلة نصّية إليها و سوف تُستَخدَم كَرسالة خطأ.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">a_method_used_for_validation_purposes
    errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">base</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="hljs-string"><span class="str">"This person is invalid because ..."</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></code></pre>

<h3 id="76-محو-الأخطاء-errorsclear">
	7.6 محو الأخطاء errors.clear
</h3>

<p>
	تُستخدم وسيلة <code>clear</code> عندما تريد أن تمسح كل رسائل الخطأ في مجموعة الأخطاء <code>errorscollection</code> . بالطبع مناداة <code>errors.clear</code> لكائن غير صالح لن يجعله ساريًا أو صالحًا للاستخدام. مجموعة الأخطاء سوف تُفرّغ ، لكن المرة القادمة التي تستدعي فيها <code>?valid</code> أو أي وسيلة تحاول أن تحفظ الكائن في قاعدة البيّانات ، سوف تعمل التحقيقات مجّددًا. لو فشل أيّ من التحقيقات سوف تُملأ مجموعة الأخطاء مجددًا.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">length</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">minimum</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pln">
person</span><span class="pun">.</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; false</span></span><span class="pln">
person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln">
 </span><span class="hljs-comment"><span class="com"># =&gt; ["can't be blank", "is too short (minimum is 3 characters)"]</span></span><span class="pln">

person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">clear
person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">empty</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; true</span></span><span class="pln">

person</span><span class="pun">.</span><span class="pln">save </span><span class="hljs-comment"><span class="com"># =&gt; false</span></span><span class="pln">

person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln">
</span><span class="hljs-comment"><span class="com"># =&gt; ["can't be blank", "is too short (minimum is 3 characters)"]</span></span></code></code></pre>

<h3 id="77-حجم-الأخطاء-errorssize">
	7.7 حجم الأخطاء errors.size
</h3>

<p>
	ترد وسيلة <code>size</code> بالعدد الكلي لرسائل الأخطاء للكائن.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code>
<code class="hljs avrasm"><span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> presence</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> length</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> minimum</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">new</span></span><span class="pln">
person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">valid</span></span><span class="pun">?</span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com"># =&gt; false</span></span><span class="pln">
person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">errors</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">size</span></span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com"># =&gt; 2</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">new</span></span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Andrea"</span></span><span class="pun">,</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"andrea@example.com"</span></span><span class="pun">)</span><span class="pln">
person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">valid</span></span><span class="pun">?</span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com"># =&gt; true</span></span><span class="pln">
person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">errors</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">size</span></span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com"># =&gt; 0</span></span></code></code></pre>

<h2 id="8-تقديم-أخطاء-التحقيق-للعرض-displaying-validation-errors-in-views">
	8 تقديم أخطاء التحقيق للعرض Displaying Validation Errors in Views
</h2>

<p>
	بمجرّد إنشائك نموذجًا و إضافة تحقيقات ، لو كان النموذج مصنوع بواسطة شكل المواقع ، من المحتمل أن تريد عرض رسالة عند فشَل أحد التحقيقات. لأن كل تطبيق يعالج هذا النوع من الأشياء بطريقة مختلفة ، لا يتضمّن Rails أي view helpers لتساعدك على توليد تلك الرسائل بصورة مباشرة. مع ذلك ، بسبب فرط الوسائل التي يعطيك إيّاها Rails لكي تتعامل مع التحقيقات بشكل عام، تكون العملية سهلة جدّا لإنشاء ما يخصّك منها. بالاضافة إلى ذلك ، عند إنتاج هيكل رئيسي مساعد ، سوف يضع Rails بعض ERB إلى <code>_form.html.erb</code> الذي تنتجه والذي يعرض قائمة بكل الأخطاء في النموذج. بافتراض أن لدينا نموذج تم حفظه في متغيّر باسم <code>article@</code> ، سيبدو كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code><code><code><code>
<code class="hljs xml"><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">any</span><span class="pun">?</span><span class="pln"> %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"error_explanation"</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> pluralize</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">count</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"error"</span></span><span class="pun">)</span><span class="pln"> %&gt;</span></span><span class="pln"> prohibited this article from being saved:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">

    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">full_messages</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">each</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">msg</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> msg %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">div</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span></code></code></code></code></code></pre>

<p>
	علاوةً على ذلك، إذا استخدمت تصميم Rails من المساعدين لتولّد تصميماتك(نماذجك)، عندما يحدث خطأ تحقيق في الحقل سوف تنتج <code>&lt;div&gt;</code> إضافي بالقرب من المدخل.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code><code><code><code>
<code class="hljs applescript"><span class="tag">&lt;</span><span class="hljs-keyword"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-type"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-string"><span class="atv">"field_with_errors"</span></span><span class="tag">&gt;</span><span class="pln">
 </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="hljs-property"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-string"><span class="atv">"article_title"</span></span><span class="pln"> </span><span class="hljs-property"><span class="atn">name</span></span><span class="pun">=</span><span class="hljs-string"><span class="atv">"article[title]"</span></span><span class="pln"> </span><span class="atn">size</span><span class="pun">=</span><span class="hljs-string"><span class="atv">"30"</span></span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="hljs-string"><span class="atv">"text"</span></span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="hljs-string"><span class="atv">""</span></span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/</span><span class="hljs-keyword"><span class="tag">div</span></span><span class="tag">&gt;</span><span class="pln">`</span></code></code></code></code></code></pre>

<p>
	يمكنك حين ذاك تشكيل ال <code>div</code> كما تريد. الهيكل الافتراضى الذي ينتجه Rails على سبيل المثال يضيف قاعدة ال CSS هذِهِ.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9032_8" style="">
<code><code><code><code>
<code class="hljs css"><span class="hljs-class"><span class="pun">.</span><span class="pln">field_with_errors</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">padding</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="lit">px</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">color</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> red</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">display</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> table</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></code></code></code></code></pre>

<p>
	هذا يعني أنّ أي حقل به خطأ ينتهي به الحال بإطار أحمر بعرض 2 بكسل.
</p>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/active_record_validations.html" rel="external nofollow">Ruby on Rails</a>.
</p>
]]></description><guid isPermaLink="false">591</guid><pubDate>Tue, 02 Jan 2018 06:02:00 +0000</pubDate></item><item><title>Active Record Validations: &#x623;&#x646;&#x648;&#x627;&#x639;&#x647;&#x627; &#x648;&#x62E;&#x64A;&#x627;&#x631;&#x627;&#x62A;&#x647;&#x627; &#x627;&#x644;&#x634;&#x627;&#x626;&#x639;&#x629;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%88%D8%AE%D9%8A%D8%A7%D8%B1%D8%A7%D8%AA%D9%87%D8%A7-%D8%A7%D9%84%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-r579/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_12/25-2.png.ae5acc85db853d1132ce02af9c04d074.png" /></p>

<p>
	في الدرسين السابقين ألقينا <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-r573/" rel="">نظرة عامة حول التحقيقات في Active Record</a> وتعرّفنا على <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D9%85%D8%B3%D8%A7%D8%B9%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D8%A7%D8%AA-r576/" rel="">مساعدات التحقيقات</a> وسنتابع في هذا الدرس تعلم الخيارات الشائعة للتحقيقات وأنواع التحقيقات.
</p>

<h2 id="3-خيارات-تحقيق-شائعة-common-validation-options">
	3 خيارات تحقيق شائعة common Validation Options
</h2>

<p>
	هذه خيارات تحقيق شائعة
</p>

<h3 id="31-اسمح-بمجموعة-خالية-allownil">
	3.1 اسمح بمجموعة خالية allow_nil
</h3>

<p>
	خيار <code>allow_nil</code> يتجاوز التحقيقات عندما تكون القيمة التي يجري عليها التحقيق <code>nil</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Coffee</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">size</span><span class="pun">,</span><span class="pln"> inclusion</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">in</span><span class="pun">:</span><span class="pln"> </span><span class="pun">%</span><span class="pln">w</span><span class="pun">(</span><span class="pln">small medium large</span><span class="pun">),</span><span class="pln">
    message</span><span class="pun">:</span><span class="pln"> </span><span class="str">"%{value} is not a valid size"</span><span class="pln"> </span><span class="pun">},</span><span class="pln"> allow_nil</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	لكل الخيارات لمضمون الرسالة من فضلك اقرأ الفقرة (<strong>3.3 أمر الإرسال :message</strong>).
</p>

<h3 id="32-اسمح-بالفراغ-allowblank">
	3.2 اسمح بالفراغ :allow_blank
</h3>

<p>
	خيار <code>:allow_blank</code> مماثل لخيار <code>:allow_nil</code> . الخيار سوف يتجاوز التحقيقات إذا كانت القيمة <code>blank?</code> (فراغ). مثل مجموعة أو سلسلة فارغة على سبيل المثال.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Topic</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">title</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">length</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="kwd">is</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pln"> </span><span class="pun">},</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">allow_blank</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-constant"><span class="typ">Topic</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">title</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">""</span></span><span class="pun">).</span><span class="pln">valid</span><span class="pun">?</span><span class="pln">  </span><span class="hljs-comment"><span class="com"># =&gt; true</span></span><span class="pln">
</span><span class="hljs-constant"><span class="typ">Topic</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">title</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">nil</span></span><span class="pun">).</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; true</span></span></code></pre>

<h3 id="33-أمر-الإرسال-message">
	3.3 أمر الإرسال :message
</h3>

<p>
	كما رأيت مسبقًا ، خيار <code>:message</code> يسمح لك بتحديد الرسالة التي ستضاف إلى مجموعة الأخطاء عند فشل التحقيق. عندما لا يُستخدم هذا الخيار ، سيقوم Active Record باستخدام الوضع الافتراضي لرسائل الخطأ لكل مساعد تحقيق. يقبل خيار <code>:message</code> أي <code>string</code> أو  <code>proc</code>) و proc هو قالب من الكود الذي يتم إضافته أو قيده لمجموعة من المتغيّرات المحلّية ، و عندما يضاف يمكن أن يتم استدعاء هذا القالب في أكثر من سياق و يزال ويمكنه الوصول لتلك المتغيرات). قيمة رسالة سلسلة نصّية <code>String :message</code> يمكن –اختياريًا- أن تحتوي على أي أو كلّا من <code>%{value}</code> و <code>%{attribute}</code> و <code>%{model}</code> ، و التي سيتم تبديلها تلقائيّا عند فشل التحقيق. يتم هذا التغيير باستخدام I18n gem ، وماسك المكان يجب أن يتطابق تمامًا ، لا يُسمح بالمساحات. قيمة <code>proc :message</code> تُعطى تعبيرين ، الكائن الذي يتم التحقق منه ، و جدول تقطيع بأزواج <code>key-value</code> و هم <code>:model</code> و <code>:attribute</code> و <code>:value</code> .
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  </span><span class="hljs-comment"><span class="com"># Hard-coded message</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">message</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"must be given please"</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">

  </span><span class="hljs-comment"><span class="com"># Message with dynamic attribute value. %{value} will be replaced with</span></span><span class="pln">
  </span><span class="hljs-comment"><span class="com"># the actual value of the attribute. %{attribute} and %{model} also</span></span><span class="pln">
  </span><span class="hljs-comment"><span class="com"># available.</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">age</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">numericality</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">message</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"%{value} seems wrong"</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">

  </span><span class="hljs-comment"><span class="com"># Proc</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">username</span></span><span class="pun">,</span><span class="pln">
    </span><span class="hljs-symbol"><span class="pln">uniqueness</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="hljs-comment"><span class="com"># object = person object being validated</span></span><span class="pln">
      </span><span class="hljs-comment"><span class="com"># data = { model: "Person", attribute: "Username", value: &lt;username&gt; }</span></span><span class="pln">
      </span><span class="hljs-symbol"><span class="pln">message</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">-&gt;(</span><span class="kwd">object</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
        </span><span class="hljs-string"><span class="str">"Hey </span><span class="hljs-subst"><span class="str">#{object.name}</span></span><span class="str">!, </span><span class="hljs-subst"><span class="str">#{data[</span><span class="hljs-symbol"><span class="str">:value</span></span><span class="str">]}</span></span><span class="str"> is taken already! Try again </span><span class="hljs-subst"><span class="str">#{</span><span class="hljs-constant"><span class="str">Time</span></span><span class="str">.zone.tomorrow}</span></span><span class="str">"</span></span><span class="pln">
      </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
    </span><span class="pun">}</span></code></pre>

<h3 id="34-على-on">
	3.4 على :on
</h3>

<p>
	خيار <code>:on</code> يدعك تحدد متى ينبغي أن يجرى التحقيق. السلوك الافتراضي لكل مساعدين التحقيق المدمجين أن تجري عند الحفظ (عندما تكون تنشىء سجل جديد و عندما تقوم بتحديثه). إذا أردت تغير ذلك يمكنك استخدام <code>on: :create</code> لإجراء التحقيق فقط عند إنشاء سجل جديد ، أو <code>on: :update</code> لإجرائه عندما يتم تحديث السجل فقط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs oxygene"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  </span><span class="com"># it will be possible </span><span class="hljs-keyword"><span class="com">to</span></span><span class="com"> update email </span><span class="hljs-keyword"><span class="com">with</span></span><span class="com"> a duplicated value</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">email</span><span class="pun">,</span><span class="pln"> uniqueness</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">on</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">:</span><span class="hljs-keyword"><span class="pln">create</span></span><span class="pln">

  </span><span class="com"># it will be possible </span><span class="hljs-keyword"><span class="com">to</span></span><span class="com"> </span><span class="hljs-keyword"><span class="com">create</span></span><span class="com"> the </span><span class="hljs-keyword"><span class="com">record</span></span><span class="com"> </span><span class="hljs-keyword"><span class="com">with</span></span><span class="com"> a non-numerical age</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">age</span><span class="pun">,</span><span class="pln"> numericality</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">on</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">:</span><span class="pln">update

  </span><span class="com"># the </span><span class="hljs-keyword"><span class="com">default</span></span><span class="com"> (validates </span><span class="hljs-keyword"><span class="com">on</span></span><span class="com"> both </span><span class="hljs-keyword"><span class="com">create</span></span><span class="com"> </span><span class="hljs-keyword"><span class="com">and</span></span><span class="com"> update)</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> presence</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يمكنك أيضًا استخدام <code>on:</code> لتحديد سياق مخصّص. يحتاج السياق المخصص إلى تنشيط بشكل صريح من خلال إرسال اسمه إلى <code>valid?</code> أو <code>invalid?</code> أو <code>save</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">uniqueness</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">on</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">account_setup</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">age</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">numericality</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">on</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">account_setup</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span></code></pre>

<p>
	.(person.valid? (:account_setup يستثنى كلا التحقيقين بدون حفظ النموذج. و <code>(person.save(context: :account_setup)</code> يتحقق من الشخص في سياق <code>account_setup</code> قبل الحفظ. على منشّطات صريحة ، يتم التحقق من النموذج بمحققات تابعة لهذا السياق فقط و محققات بدون سياق.
</p>

<h2 id="4-تحقيقات-صارمة-strict-validations">
	4 تحقيقات صارمة Strict Validations
</h2>

<p>
	يمكنك أيضًا اختيار محققات لتكون مشدّدة و تنشّط <code>ActiveModel : :StrictValidationFailed</code> عندما يكون الكائن غير ساري.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">strict</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pun">.</span><span class="pln">valid</span><span class="pun">?</span><span class="pln">  </span><span class="hljs-comment"><span class="com"># =&gt; ActiveModel::StrictValidationFailed: Name can't be blank</span></span></code></pre>

<p>
	يوجد أيضًا امكانية لعمل استثناء مخصّص على خيار <code>:strict</code> .
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">token</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">uniqueness</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">strict</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-constant"><span class="typ">TokenGenerationException</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pun">.</span><span class="pln">valid</span><span class="pun">?</span><span class="pln">  </span><span class="hljs-comment"><span class="com"># =&gt; TokenGenerationException: Token can't be blank</span></span></code></pre>

<h2 id="5-التحقيق-المشروط-conditional-validation">
	5 التحقيق المشروط conditional validation
</h2>

<p>
	في بعض الأوقات سيبدو من المنطقي أن يتم التحقق من كائن فقط عندما تُوفى معايير فلترة معيّنة. يمكنك عمل ذلك باستخدام خيارات <code>:if</code> و <code>:unless</code> ، التي يمكن أن تأخذ رمز ، سلسلة نصّية ، أو proc. يمكنك استخدام خيار <code>:if</code> عندما تريد أن تحدد متى ينبغى أن يجرى التحقيق. إذا كنت تريد أن تحدد متى لا ينبغي أن يجري التحقيق إذن استخدم خيار <code>:unless</code>
</p>

<h3 id="51-استخدام-رمز-مع-إذا-و-إذا-لم-using-a-sympol-with-if-and-unless">
	5.1 استخدام رمز مع إذا و إذا لم Using a Sympol with :if and :unless
</h3>

<p>
	يمكنك مصادقة خيارات <code>:if</code> و <code>:unless</code> مع رمز تناظر مع اسم الوسيلة التي سوف تُستدعى قبل حدوث التحقيق مباشرةً. هذا هو أكثر الخيارات الشائعة استخدامًا.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Order</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">card_number</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="kwd">if</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">paid_with_card</span><span class="pun">?</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">paid_with_card</span><span class="pun">?</span><span class="pln">
    payment_type </span><span class="pun">==</span><span class="pln"> </span><span class="hljs-string"><span class="str">"card"</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<h3 id="52-استخدام-بروك-مع-إذا-و-إذا-لم-using-a-proc-with-if-and-unless">
	5.2 استخدام بروك مع إذا و إذا لم Using a Proc with :if and :unless
</h3>

<p>
	أخيرًا يمكن ربط <code>:if</code> و <code>:unless</code> مع كائن proc ، الذي سيتم استدعاؤه. استخدام Proc object يعطيك القدرة على كتابة شرط داخلي بدلًا من وسيلة منفصلة. هذا الخيار الأفضل لها فالاستخدام مع برامج السطر الواحد (ادخال نصّي إلى ال <code>command-line</code> الخاص بنظم تشغيل تقوم بوظائف ما بسطر واحد من الكود)
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Account</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">password</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">confirmation</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln">
    </span><span class="hljs-symbol"><span class="kwd">unless</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Proc</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">|</span><span class="pln">a</span><span class="pun">|</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">blank</span><span class="pun">?</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<h3 id="53-تجميع-التحقيقات-الشرطية-grouping-conditional-validations">
	5.3 تجميع التحقيقات الشرطيّة Grouping Conditional Validations
</h3>

<p>
	في بعض الأوقات يكون من المفيد أن يستخدم تحقيقات متعددة نفس الشرط. يمكن الوصول لذلك بسهولة من خلال <code>with_options</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">User</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  with_options </span><span class="hljs-symbol"><span class="kwd">if</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">is_admin</span><span class="pun">?</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">admin</span><span class="pun">|</span><span class="pln">
    admin</span><span class="pun">.</span><span class="pln">validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">password</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">length</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">minimum</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">10</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
    admin</span><span class="pun">.</span><span class="pln">validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	كل التحقيقات بداخل قالب <code>with_options</code> سيكون قد تجاوز تلقائيّا بالفعل شرط <code>?if: :is_admin</code> .
</p>

<h3 id="54-ضمدمج-شروط-التصديق-combining-validation-conditions">
	5.4 ضم/دمج شروط التصديق Combining Validation Conditions
</h3>

<p>
	من ناحية أخرى ، عندما يحدد شروط متعددة إذا كان التحقيق ينبغي أن يجري أم لا ، يُمكن استخدام مصفوفة. إضافة إلى ذلك يمكنك تطبيق كلا من <code>:if</code> و <code>:unless</code> على نفس التحقيق.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1717_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Computer</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">mouse</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln">
                    </span><span class="hljs-symbol"><span class="kwd">if</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">"market.retail?"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">desktop</span><span class="pun">?</span></span><span class="pun">],</span><span class="pln">
                    </span><span class="hljs-symbol"><span class="kwd">unless</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Proc</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">|</span><span class="pln">c</span><span class="pun">|</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">trackpad</span><span class="pun">.</span><span class="pln">present</span><span class="pun">?</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يجري التحقيق فقط عندما يكون شروط <code>:if</code> محققة (قيمتها ture) ، و كل شروط <code>:unless</code> غير محقّقة.
</p>

<p>
	سنتابع في الدرس القادم والأخير ما بقي من هذا <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D9%85%D8%B3%D8%A7%D8%B9%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D8%A7%D8%AA-r576/ruby%20on%20rails%20103" rel="">الدليل التعليمي</a> حول تحقيقات Active Record.
</p>

<p>
	المصدر:<br><a href="http://guides.rubyonrails.org/active_record_validations.html" rel="external nofollow">توثيقات Ruby on Rails</a>.
</p>
]]></description><guid isPermaLink="false">579</guid><pubDate>Mon, 25 Dec 2017 07:01:00 +0000</pubDate></item><item><title>Active Record Validations: &#x645;&#x633;&#x627;&#x639;&#x62F;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x62D;&#x642;&#x64A;&#x642;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D9%85%D8%B3%D8%A7%D8%B9%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%8A%D9%82%D8%A7%D8%AA-r576/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_12/19-2.png.e13beb718112992cc36fc9e0b0f13fba.png" /></p>

<p>
	في <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-r573/" rel="">الدرس السابق</a> ألقينا نظرة عامة حول التحقيقات في Active Record وسنتابع في هذا الدرس تعلم مساعدات التحقيقات
</p>

<h2 id="2-مساعدات-التحقيقات-validation-helpers">
	2 مساعدات التحقيقات validation helpers
</h2>

<p>
	يعرض Active Record العديد من مساعدات تحقيقات المعرفة مسبقًا التي يمكنك استخدامها مباشرة داخل تعريفات فئتك. تدعم تلك المساعدات قواعد تحقيقات شائعة. فى كل مرة يفشل تحقيق ، تضاف رسالة خطأ الى مجموعة أخطاء الكائن ، و ترتبط تلك الرسالة بالخاصية التي يتم التحقق منها. يقبل كل مساعد رقم اعتباطي من أسماء الخواص ، لذلك يمكنك إضافة نفس نوع التحقيق للعديد من الخواص بسطر كود واحد. جميعم يقبل خيارات <code>on:</code> و <code>message:</code> الاثنين يحددان متى يجب أن يتم اجراء التحقيق ، و أي رسالة يجب إضافتها إلى مجموعة الأخطاء فى حال فشلها ، على الترتيب. خيار ال <code>on:</code> يأخذ القيم <code>create:</code> (أنشىء) أو <code>:update:</code> (حدّث). هناك رسالة خطأ افتراضية لكل واحد من مساعدات التحقيق. تُستَخدم تلك الرسائل عندما لا يكون خيار <code>message:</code> محددًا. فلنأخذ نظرة على كل واحد من مساعدات التحقيق.
</p>

<h3 id="21-القبول-acceptance">
	2.1 القبول acceptance
</h3>

<p>
	تتأكد هذه الطريقة اذا ما كان الـ checkbox فى واجهة تشغيل المستخدم معلّمًا عندما يتم إرسال أي نموذج. يتم استخدام هذه الطريقة غالبًا عندما يكون المستخدم بحاجة لقبول شروطك لتقديم الخدمة ، يؤكد على قراءة نص معيّن ، أو أي مفهوم مشابه.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">terms_of_service</span><span class="pun">,</span><span class="pln"> acceptance</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	يجري هذا الفحص فقط إذا كانت شروط العمل ليست nil. رسالة الخطأ الافتراضية لهذا المساعد هي “must be acceptd” أي يجب أن تقبل. يمكن أيضًا تجاوز الرسالة المخصصة من خلال خيار الرسالة message.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">terms_of_service</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">acceptance</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">message</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'must be abided'</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يمكن أيضًا أن تستقبل خيار <code>accept:</code> التي تحدد القيم المسموح بها لأن تعتبر مقبولة. إنها تعود كما هو افتراضي إلى <code>[`1` , true]</code> و يمكن أن تتغير بسهولة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs css"><span class="hljs-tag"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-tag"><span class="typ">Person</span></span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-tag"><span class="typ">ApplicationRecord</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="pln">validates</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">terms_of_service</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">acceptance</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">accept</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-string"><span class="str">'yes'</span></span><span class="pln"> </span></span></span></span><span class="pun">}</span><span class="pln">
  </span><span class="hljs-tag"><span class="pln">validates</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">eula</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">acceptance</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">accept</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'TRUE'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'accepted'</span></span><span class="pun">]</span><span class="pln"> </span></span></span></span><span class="pun">}</span><span class="pln">
</span><span class="hljs-tag"><span class="kwd">end</span></span></code></pre>

<p>
	هذا التحقيق مخصص جدًا لتطبيقات المواقع و هذا “القبول” acceptance لا يحتاج إلى أن يسجّل في أي مكان بقاعدة البيانات. إذا لم يكن لديك مجال له ، سوف ينشىء المساعد خاصية افتراضية. إذا كان لا يوجد مجال في قاعدة بياناتك يجب أن يكون خيار القبول مفعّلًا أو يتضمن <code>true</code> وإلا لن يجري التحقيق.
</p>

<h3 id="22-validatesassociated-مرتبط-بالتحقيق">
	2.2 validates.associated مرتبط بالتحقيق
</h3>

<p>
	يجب أن تستخدم هذا المساعد عندما يكون لنموذجك ارتباطات بنماذج أخرى و هم أيضًا بحاجة إلى أن يتم التحقق منهم. عندما تحاول حفظ كائن ، ?valid سيتم استدعائها لكل واحد من الكائنات المرتبطة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Library</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  has_many </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">books</span></span><span class="pln">
  validates_associated </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">books</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	هذا التحقيق سوف يعمل مع كل أنواع الارتباطات.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تحذير: </strong>لا تستخدم <code>validates_associated</code> على نهايتي الـ associations. ستقوم كل واحدة باستدعاء الأخرى فى دائرة لا متناهية.
		</p>
	</div>
</blockquote>

<p>
	رسالة الخطأ الافتراضية لـ <code>validates_associated</code> هي “is invalid” أي غير صالح. لاحظ أن كل associated object لن يحتوي على مجموعة أخطائه ، الأخطاء لا تتصاعد إلى نموذج الاستدعاء.
</p>

<h3 id="23-التأكيد-confirmation">
	2.3 التأكيد confirmation
</h3>

<p>
	يجب أن تستخدم هذا المساعد عندما يكون لديك حقول نصوص التي يجب أن تستقبل نفس المحتوى بالضبط. على سبيل المثال من الممكن أن تكون تريد التأكيد على عنوان بريد إلكتروني أو كلمة مرور. هذا التحقيق ينشىء خاصية افتراضية بنفس اسم الحقل الذي يجب أن يتم التأكيد عليه بـ”_confirmation” (تأكيد) مُلحق.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">confirmation</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	فى قالب العرض خاصتك يمكن أن تستخدم شيئًا مثل:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="pun">&lt;%=</span><span class="pln"> text_field </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">person</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pln"> %&gt;
</span><span class="pun">&lt;%=</span><span class="pln"> text_field </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">person</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email_confirmation</span></span><span class="pln"> %&gt;</span></code></pre>

<p>
	هذا الفحص يجري فقط إذا كان <code>email_confirmation</code> ليس <code>nil</code>. لكي تطلب معلومات تأكد من إضافة presence check لخاصية التأكيد:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">confirmation</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email_confirmation</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يوجد خيار <code>case_sensitive</code> الذي يمكنك استخدامه لتحدد إذا ما كان من قيود التأكيد أن يكون مستشعرًا لحالة الحروف أم لا (أي يفرق بين الحروف الـ capital و الـ small). والخيار الافتراضي له هو <code>true</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">confirmation</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">case_sensitive</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">false</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	رسالة الخطأ الافتراضية لهذا المساعد هي “doesn’t match confirmation” أي لا يتوافق مع التأكيد.
</p>

<h3 id="24-استثناء-exclusion">
	2.4 استثناء exclusion
</h3>

<p>
	هذا المساعد يصدّق أن قيم الخواص ليست متضمّنة فى مجموعة معطاة. في الحقيقة ، تلك المجموعة يمكن أن تكون أي كائن غير قابل للعد.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Account</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">subdomain</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">exclusion</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="kwd">in</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="pun">%</span><span class="pln">w</span><span class="pun">(</span><span class="pln">www us ca jp</span><span class="pun">)</span></span><span class="pun">,</span><span class="pln">
    </span><span class="hljs-symbol"><span class="pln">message</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"%{value} is reserved."</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يمتلك مساعد الاستثناء خيار <code>in:</code> الذي يستقبل مجموعة من القيم التي لن تقبل الخصائص المتحقق منها. خاصية <code>in:</code> لها اسم آخر متعارف عليه هو <code>within:</code> و الذي يمكن استخدامه لنفس الوظيفة. هذا المثال يستخدم خيار <code>message:</code> ليعرض كيف يمكن تضمين قيمة الخصّيصة. من أجل خيارات مفصّلة/كاملة لمتغير الرسالة. رسالة الخطأ الافتراضيّة هى “is reversed”
</p>

<h3 id="25-الشكلالتصميم-format">
	2.5 الشكل/التصميم format
</h3>

<p>
	هذا المساعد يتحقق من قيم الخواص باختبار اذا ما كانوا تطابق تعبير اعتيادي معطى ، الذي يتم تحديده باستخدام خيار <code>with:</code> .
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Product</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">legacy_code</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">format</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="kwd">with</span><span class="pun">:</span></span><span class="pln"> </span><span class="str">/\</span><span class="hljs-constant"><span class="str">A</span></span><span class="str">[a-zA-</span><span class="hljs-constant"><span class="str">Z</span></span><span class="str">]+\z/</span><span class="pun">,</span><span class="pln">
    </span><span class="hljs-symbol"><span class="pln">message</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"only allows letters"</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	بدلًا من ذلك يمكنك اختيار ألا تطابق الخواص المحددة expression معين باستخدام خيار <code>without:</code> . رسالة الخطأ الافتراضية هى “is invalid” .
</p>

<h3>
	2.6 التضمين inclusion
</h3>

<p>
	هذا المساعد يتحقق أن قيم الخواص متضمنة فى مجموعة معينة. هذه المجموعة يمكن أن تكون أي كائن غير معدود.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Coffee</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">size</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">inclusion</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="kwd">in</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="pun">%</span><span class="pln">w</span><span class="pun">(</span><span class="pln">small medium large</span><span class="pun">)</span></span><span class="pun">,</span><span class="pln">
    </span><span class="hljs-symbol"><span class="pln">message</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"%{value} is not a valid size"</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	مساعد التضمين inclusion helper لديه خيار <code>in:</code> الذي يستقبل مجموعة من القيم التي ستكون مقبولة. خيار <code>in:</code> لديه اسم آخر هو <code>within:</code> الذي يمكن استخدامه بدلًا منه لنفس الوظيفة. يستخدم المثال السابق خيار الـ <code>message:</code> ليبين كيف يمكن تضمين قيمة الخصّيصة. رسالة الخطأ الافتراضية لهذا المساعد هي “is not included in the list”.
</p>

<h3 id="27-الطول">
	2.7 الطول
</h3>

<p>
	هذا المساعد يتحقق من طول قيم الخصائص. إنه يدعم خيارات مختلفة حتى يتسنّى للمستخدم تحديد قيود الطول بطرق مختلفة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs css"><span class="hljs-tag"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-tag"><span class="typ">Person</span></span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-tag"><span class="typ">ApplicationRecord</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="pln">validates</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">length</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">minimum</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pln"> </span></span></span></span><span class="pun">}</span><span class="pln">
  </span><span class="hljs-tag"><span class="pln">validates</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">bio</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">length</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">maximum</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">500</span></span><span class="pln"> </span></span></span></span><span class="pun">}</span><span class="pln">
  </span><span class="hljs-tag"><span class="pln">validates</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">password</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">length</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="kwd">in</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">6</span></span><span class="lit">.</span><span class="pun">.</span><span class="hljs-number"><span class="lit">20</span></span><span class="pln"> </span></span></span></span><span class="pun">}</span><span class="pln">
  </span><span class="hljs-tag"><span class="pln">validates</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">registration_number</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">length</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="kwd">is</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">6</span></span><span class="pln"> </span></span></span></span><span class="pun">}</span><span class="pln">
</span><span class="hljs-tag"><span class="kwd">end</span></span></code></pre>

<p>
	خيارات قيود الطول المتاحة هي:
</p>

<ul>
<li>
		<code>minimum: </code>(أقل حد) الخاصية لا يمكن أن تكون أقل من الطول المحدد
	</li>
	<li>
		<code>maximum: </code> (أقصى حد) الخاصية لا يمكن أن تكون أكثر من الطول المحدد.
	</li>
	<li>
		<code>in: (أو within:)</code> (في حدود) طول الخاصية يجب أن يكون متضمن في أبعاد معيّنة. قيمة هذا الخيار يجب أن يكون نطاق/مدى.
	</li>
	<li>
		<code>is: </code>(يساوي) طول الخاصية يجب أن يكون مساويًا للقيمة المعطاه.
	</li>
</ul>
<p>
	رسالة الخطأ الافتراضيّة تعتمد على نوع تحقيق الطول المُجرى. يمكنك تخصيص هذه الرسائل باستخدام خيارات <code>wrong_length:</code> (طول خطأ) و <code>too_long:</code> (طويل جدًا) و <code>too_short:</code> (قصير جدًا) ، و  <code>{count}</code> كماسك للمكان للرقم المناظر لقيد الطول المُستخدم. يمكنك أيضًا استخدام خيار <code>message:</code> لتحدد رسالة الخطأ.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">bio</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">length</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">maximum</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">1000</span></span><span class="pun">,</span><span class="pln">
    </span><span class="hljs-symbol"><span class="pln">too_long</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"%{count} characters is the maximum allowed"</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	لاحظ أن رسائل الأخطاء هي جمع (على سبيل المثال “قصير جدًا( الحد الأدنى هو <code>{count}</code> أحرف)”). لهذا السبب عندما يكون الحد الأدنى هو 1 يجب أن توفر رسالة مخصصة أو استخدم <code>presence : true</code> بدلًا من ذلك. عندما يمتلك <code>in:</code> أو <code>within:</code> حد أدنى 1 ينبغى عليك إما توفير رسالة خطأ مخصصة أو استدعاء presence طبقًا لأولوية الطول.
</p>

<h3 id="28-العددية-numericality">
	2.8 العددية numericality
</h3>

<p>
	هذا المساعد يتحقق أن خواصّك بها قيم عددية فقط. افتراضيّا ، سوف يقوم بالتحقق من وجود رقم صحيح integer أو عدد عشري floating point number. لتحدد السماح بالأرقام الصحيحة فقط اضبط <code>only_integer:</code> على <code>true</code>. إذا قمت بضبط <code>only_integer:</code> على <code>true</code> ، ستقوم باستخدام:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs tex"><span class="str">/</span><span class="hljs-command"><span class="str">\A</span></span><span class="hljs-special"><span class="str">[</span></span><span class="str">+-</span><span class="hljs-special"><span class="str">]</span></span><span class="str">?</span><span class="hljs-command"><span class="str">\d</span></span><span class="str">+</span><span class="hljs-command"><span class="str">\z</span></span><span class="str">/</span></code></pre>

<p>
	عبارة اعتيادية للتحقق من قيمة الخصيصة. فيما عدا ذلك ستقوم بتحويل القيمة الى رقم باستخدام <code>float</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Player</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">points</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">numericality</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">games_played</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">numericality</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">only_integer</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	بجانب <code>only_integer:</code> هذا المساعد يقبل أيضًا هذه الخيارات لإضافة قيود على القيم المقبولة:
</p>

<ul>
<li>
		<code>greater_than:</code> تحديد القيمة الصُغرى للقيمة المُضافة
	</li>
	<li>
		<code>greater_than_or_equal_to:</code> تحديد القيمة الصُغرى مع إمكانية المساواة
	</li>
	<li>
		<code>equal_to:</code> القيمة المُضافة يجب أن تساوي
	</li>
	<li>
		<code>less_than:</code> تحديد القيمة الكُبرى للقيمة المضافة
	</li>
	<li>
		<code>less_than_or_equal_to:</code> تحديد القيمة الكُبرى مع إمكانية المساواة
	</li>
	<li>
		<code>other_than:</code> القيمة المُضافة يجب ألّا تساوي تلك القيمة
	</li>
	<li>
		<code>Odd:</code> القيمة المضافة يجب أن تكون فردية
	</li>
	<li>
		<code>Even:</code> القيمة المضافة يجب أن تكون زوجية
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: الضبط الافتراضي للعددية لا يسمح بقيم nil. يمكنك استخدام خيار <code>allow_nil: true</code> للسماح بها.
		</p>
	</div>
</blockquote>

<p>
	رسالة الخطأ الافتراضية هى “is not a number” (ليس رقمًا).
</p>

<h3 id="29-وجود-presence">
	2.9 وجود presence
</h3>

<p>
	هذا المساعد يتحقق أن الخصائص المحددة ليست فارغة. إنها تستخدم طريقة <code>?blank</code> لتكتشف إذا كانت القيمة إما <code>nil</code> أو سلسلة فارغة blank string – و التي تكون سلسلة فارغة أو تتكون من مساحة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">login</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إذا أردت أن تتأكد أن الارتباطات موجودة سوف تحتاج أن تختبر إذا ما كان الكائن نفسه موجودًا ، و ليس المفتاح الخارجي المستخدم لتنظيم الارتباط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">LineItem</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  belongs_to </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">order</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">order</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يجب أن تحدد خيار <code>inverse:</code> للرابطة حتى تتحقق من السجلّات المرتبطة التي يجب أن تكون موجودة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Order</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  has_many </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">line_items</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">inverse_of</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">order</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إذا تحققت من وجود كائن من خلال علاقة <code>has_one</code> أو <code>has_many</code> سوف يفحص إذا ما كان الكائن ليس <code>?blank</code> (فارغ) ولا <code>marked_for_destruction</code> (محدد للمحو)<br>
	بما أن <code>?false.blank</code> صحيح ، ينبغى أن تستخدم أحد التحقيقات التالية إذا أردت التحقق من وجود حقل <code>Boolean:</code>
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">validates</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">boolean_field_name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">inclusion</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="kwd">in</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="pun">[</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">]</span><span class="pln"> </span></span></span></span><span class="pun">}</span><span class="pln">
</span><span class="hljs-tag"><span class="pln">validates</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">boolean_field_name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">exclusion</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="kwd">in</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="pun">[</span><span class="kwd">nil</span><span class="pun">]</span><span class="pln"> </span></span></span></span><span class="pun">}</span></code></pre>

<p>
	باستخدام أحد هذه التحقيقات سوف تتأكد أن القيمة لن تكون <code>nil</code> ، مما سينتج عنه قيمة NULL فى أغلب الحالات.
</p>

<h3 id="210-الغياب-absence">
	2.10 الغياب absence
</h3>

<p>
	هذا المساعد يتحقق من أن الخصائص المحددة غائبة. إنها تستخدم وسيلة <code>?present</code> لتكتشف إذا ما كانت القيمة ليست <code>nil</code> أو <code>balnk string</code>
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">login</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">absence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إذا أردت التأكد أن التصادق غائب ، سوف تحتاج أن تختبر ما إذا كان الكائن نفسه غائبا أم المفتاح الخارجي المستخدم لتنظيم الارتباط.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="pln"> </span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">LineItem</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  belongs_to </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">order</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">order</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">absence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	حتى تتحقق من السجلات المتصادقة التي يلزم غيابها يجب أن تحدد خيار <code>inverse_of:</code> للمصادقة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Order</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  has_many </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">line_items</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">inverse_of</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">order</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إذا تحققت من غياب كائن من خلال علاقة <code>has_one</code> أو <code>has_many</code> ، سوف تفحص إذا ما كان الكائن ليس <code>?present</code> أو <code>?marked_for_destruction</code> مردودا كـ <code>false</code>. لو أردت التحقق من غياب حقل <code>Boolean</code> ينبغي أن تستخدم <code>{[validates :field_name, exclusion: {in: [true, false</code> .<br>
	رسالة الخطأ الافتراضية هى “must be blank”. أى يجب أن يكون فارغًا.
</p>

<h3 id="211-التفردالتميز-uniqueness">
	2.11 التفرّد/التميّز uniqueness
</h3>

<p>
	هذا المساعد يتحقق أن قيمة الخصيصة فريدة قبل حفظ الكائن مباشرة. إنها لا تنشىء قيد تفرّد uniqueness constraint في قاعدة البيانات ، لذلك من الممكن أن ينشىء قاعدتي بيانات مختلفتين سجلين مختلفين بنفس القيمة لعمود كنت تقصد جعله فريدًا. حتى تتجنّب ذلك يجب أن تنشىء مؤشّر متفرّد على هذا العمود في قاعدة بياناتك.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Account</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">uniqueness</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	التحقق يحدث بإجراء SQL query في جدول الوسائل ، بحثًا عن سجل موجود بنفس القيمة التي في الخاصية.<br>
	يوجد خيار <code>scope:</code> الذي يمكن استخدامه لتحديد خاصية أو أكثر تستخدم لتحديد فحص التفرّد.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Holiday</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">uniqueness</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">scope</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">year</span></span><span class="pun">,</span><span class="pln">
    </span><span class="hljs-symbol"><span class="pln">message</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"should happen once per year"</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إذا كنت تأمل فى إنشاء قيود في قاعدة البيانات لمنع أي انتهاك لتحقيق التفرّد باستخدام خيار <code>scope:</code> ، فعليك إنشاء فهرس فريد لكلا العمودين في قاعدة بياناتك. <a href="http://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html" rel="external nofollow">انظر the SQL manual</a> لتفاصيل أكثر عن فهارس العواميد المتعددة أو <a href="http://www.postgresql.org/docs/current/static/ddl-constraints.html" rel="external nofollow">the PostgresSQL manual</a> لأمثلة على قيود فريدة تنطبق على مجموعة من الأعمدة. يوجد أيضًا خيار <code>case_sensitive:</code> الذي يمكنك استخدامه لتحديد ما إذا كان قيد التفرّد سيكون حساسًا لحالة الأحرف أم لا. الضبط الافتراضي للخيار يكون ساري/صحيح <code>true</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">uniqueness</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">case_sensitive</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">false</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تحذير</strong>: لاحظ أن بعض قواعد البيانات تكون مضبوطة أن تجري أبحاث <code>case-sensitive</code> على أي حال.
		</p>
	</div>
</blockquote>

<p>
	رسالة الخطأ الافتراضية هي “has already been taken”. أي تم أخده بالفعل.
</p>

<h3 id="212-يتحقق-بـ-validateswith">
	2.12 يتحقق بـ validates_with
</h3>

<p>
	هذا المساعد ينقل السجل إلى فئة مختلفة من التصديق/التحقيق.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">GoodnessValidator</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveModel</span><span class="pun">::</span><span class="typ">Validator</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">validate</span><span class="pun">(</span><span class="pln">record</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> record</span><span class="pun">.</span><span class="pln">first_name </span><span class="pun">==</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Evil"</span></span><span class="pln">
      record</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">base</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="hljs-string"><span class="str">"This person is evil"</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates_with </span><span class="hljs-constant"><span class="typ">GoodnessValidator</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: الأخطاء المضافة إلى <code>[ record.errors[ :base</code> تتصل بحالة السجل ككل و ليس لخصّيصة معيّنة.
		</p>
	</div>
</blockquote>

<p>
	يأخذ مساعد <code>validates_with</code> فئة أو قائمة من الفئات لاستخدامها للتحقيق. لا يوجد رسالة افتراضية لرسائل الخطأ لـ <code>validates_with</code>. يجب عليك أن تضيف الأخطاء إلى مجموعة أخطاء السجل في فئة المحقق يدويًّا. لكي تنفّذ وسيلة التحقيق يجب أن تعرّف معامل السجل ، و الذي هو السجل الذي سيتم التحقق منه. على غرار باقي التحقيقات <code>validates_with</code> تأخذ خيارات <code>if:</code> و <code>unless:</code> و <code>on:</code> . إذا جرّبت أي خيار آخر سيقوم بإرسال تلك الخيارات إلى فئة المتحقق كخيارات متاحة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">GoodnessValidator</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveModel</span><span class="pun">::</span><span class="typ">Validator</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">validate</span><span class="pun">(</span><span class="pln">record</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> options</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">fields</span></span><span class="pun">].</span><span class="pln">any</span><span class="pun">?{|</span><span class="pln">field</span><span class="pun">|</span><span class="pln"> record</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="pln">field</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Evil"</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      record</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">base</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="hljs-string"><span class="str">"This person is evil"</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates_with </span><span class="hljs-constant"><span class="typ">GoodnessValidator</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">fields</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">first_name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">last_name</span></span><span class="pun">]</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	لاحظ أن المتحقق سوف يبدأ مرة واحدة فقط في دائرة عمر التطبيق ، و ليس لكل إجراء تحققي ؛ لذلك كن حذرًا عند استخدام متغيرات مقترحة/تجريبية بداخله. لو كان متحققك معقّد كفاية لدرجة أنك تريد متغيرات instance يمكنك استخدام plain old Ruby object بسهولة بدلاً من ذلك:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validate </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">person</span><span class="pun">|</span><span class="pln">
    </span><span class="hljs-constant"><span class="typ">GoodnessValidator</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pun">(</span><span class="pln">person</span><span class="pun">).</span><span class="pln">validate
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">GoodnessValidator</span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">initialize</span><span class="pun">(</span><span class="pln">person</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-variable"><span class="lit">@person</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> person
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">validate
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> some_complex_condition_involving_ivars_and_private_methods</span><span class="pun">?</span><span class="pln">
      </span><span class="hljs-variable"><span class="lit">@person</span></span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">base</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="hljs-string"><span class="str">"This person is evil"</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-comment"><span class="com"># ...</span></span><span class="pln">
</span><span class="hljs-constant"><span class="typ">End</span></span></code></pre>

<h3 id="213-تحقق-من-الكل-validateseach">
	2.13 تحقق من الكل validates_each
</h3>

<p>
	هذا المساعد يتحقق من الخصائص مقابل block. إنها لا تمتلك وظيفة تحقيق معينة ، يجب أن تنشىء واحدة باستخدام block و كل خاصية تمر إلى <code>validates_each</code> سوف تُختبر في مقابلها. في المثال التالي لا نريد الأسماء و أسماء العائلات أن تبدأ بحروف صغيرة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9298_7" style="">
<code class="hljs lua"><span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  validates_each </span><span class="pun">:</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> </span><span class="pun">:</span><span class="pln">surname </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">record</span><span class="pun">,</span><span class="pln"> attr</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">|</span><span class="pln">
    record</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">attr</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'must start with upper case'</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> value </span><span class="pun">=~</span><span class="pln"> </span><span class="pun">/</span><span class="pln">\A</span><span class="hljs-string"><span class="pun">[[:</span><span class="pln">lower</span><span class="pun">:]]</span></span><span class="pun">/</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	الـ block يستقبل السجل و اسم الخاصية و قيمة الخاصية. يمكنك فعل أي شىء ، مثل الكشف عن البيانات الصالحة داخل الـ block. إذا فشلت تحقيقاتك ينبغي عليك إضافة رسالة خطأ إلى النموذج، و من ثم جعله غير ساري.
</p>

<p>
	سنتابع في الدروس القادمة بقية هذا <a href="ruby%20on%20rails%20103" rel="">الدليل التعليمي</a> حول Active Record Validations.
</p>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/active_record_validations.html" rel="external nofollow">Ruby on Rails</a>.
</p>
]]></description><guid isPermaLink="false">576</guid><pubDate>Tue, 19 Dec 2017 08:00:00 +0000</pubDate></item><item><title>Active Record Validations : &#x646;&#x638;&#x631;&#x629; &#x639;&#x627;&#x645;&#x629;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-validations-%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-r573/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_12/12-2.png.b7724d5566507ad5be36ae3b33337135.png" /></p>

<p>
	يوضح لك هذا الدليل كيفية التأكد من صحة وضع الكائنات Objects قبل دخولها فى قاعدة البيانات، باستخدام خاصية تصديقات Active Record.
</p>

<h2 id="بعد-قراءة-هذا-الدليل-ستكون-على-دراية-بالآتي">
	1 نظرة عامة على التصديقات
</h2>

<p>
	مثال لعملية تصديق بسيطة :
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6568_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> presence</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="typ">Person</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John Doe"</span><span class="pun">).</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="com"># =&gt; true</span><span class="pln">
</span><span class="typ">Person</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">nil</span><span class="pun">).</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="com"># =&gt; false</span></pre>

<p>
	كما ترى في المثال ، يُعلِمُنا استخدام خاصية التصديق بأن ” Person ” غير ساري بدون خاصية الإسم. وكذلك Person الآخر لن يتم تثبيته في قاعدة البيانات.<br>
	قبل التعمق أكثر في التفاصيل، دعنا نتكلم أولاً عن كيفية ملائمة التصديقات في الصورة الكبيرة لتطبيقك.
</p>

<h3 id="11لماذا-نستخدم-التصديقات">
	1.1لماذا نستخدم التصديقات؟
</h3>

<p>
	تُستخدم التصديقات/التحقيقات للتأكد من أن البيانات الصالحة للاستخدام وحدها التي سيتم حفظها فى قاعدة البيانات. على سبيل المثال: يمكن أن يكون مهم لتطبيقك ضمان إدخال كل مستخدم لعنوان بريد إلكتروني و عنوان بريدي صالح للاستخدام. التحقيقات التي تكون على المستوى النموذجي Model-level Validations هى الطريقة الأمثل لضمان حفظ البيانات السارية وحدها بقاعدة بياناتك. إنها قابلة للتشغيل المتبادل على قواعد البيانات ، حيث لا يمكن للمستخدم تجاوزها أو التحايل عليها من أي مستخدم، و مناسبة للاختبار و التعامل المستمر. Rails تجعلها سهلة الاستخدام، توفّر مساعد مدمج للاستخدامات الشائعة، و تسمح لك بصناعة طرق التحقق الخاصة بك أيضًا.
</p>

<p>
	هناك العديد من الطرق للتحقق من صحة البيانات قبل حفظها فى قاعدة البيانات، بما فى ذلك بعض القيود المرتبطة أساسًا بقاعدة البيانات، تصديقات من جانب العميل client-side validations، و تصديقات على مستوى التحكم controller-level validation.
</p>

<h3 id="إليك-ملخص-السلبيات-و-الإيجابيات">
	إليك ملخّص السلبيّات و الإيجابيّات:
</h3>

<ul>
<li>
		قيود قواعد البيّانات و/أو الإجراءات المخزّنة تجعل آليّات التحقيق معتمدة على قاعدة البيّانات، و يمكن أن تجعل الإختبار و الصيانة أكثر صعوبة. مع ذلك، لو كانت قاعدة البيانات الخاصة بك تستخدم بواسطة تطبيقات أخرى، فقد تكون فكرة جيدة أن تستخدم بعض القيود على مستوى قاعدة البيّانات. بالإضافة إلى ذلك، التصديقات التي تكون على مستوى قاعدة البيانات يمكن أن تتعامل بأمان مع بعض الأشياء التي يصعب تطبيقها بالطرق الأخرى (مثل التميز/التفرّد فى الجداول المستخدمة بكثرة).
	</li>
	<li>
		يمكن للتحقيقات التي تكون من جهة العميل مفيدة، لكنها بشكل عام لا يُعتَمد عليها إذا تم استخدامها وحدها. إذا تم تنفيذها باستخدام JavaScript يمكن تجاوزها إذا كانت JavaScript غير مفعّلة في متصفّح المستخدم. مع ذلك، اذا تم دمجها مع تقنيّات أخرى يمكن أن تكون هذه التحقيقات طريقة مناسبة لتوفير ردود أفعال لمستخدمي موقعك.
	</li>
	<li>
		Controller-level validations يمكن أن تكون مغرية للاستعمال، لكن في الغالب تصبح غير عمليّة و صعبة في الاختبار و الصيانة. من الجيد أن تجعل متحكماتك صغيرة، حيث ستجعل تطبيقك محبب للاستخدام على المدى الطويل.<br>
		قم بالإختيار مما سبق فى بعض الحالات التي تراها مُناسبة. لكن رأى فريق Rails أن model-level validations هي الأكثر تناسبًا لجميع الظروف.
	</li>
</ul>
<h3 id="12لماذا-يحدث-التحقيق">
	1.2لماذا يحدث التحقيق؟
</h3>

<p>
	هناك نوعان من كائنات Active Record: تلك التي تتوافق مع صف بداخل قاعدة بياناتك، و تلك التي لا تتوافق. عندما تنشىء كائن جديد – باستخدام طريقة <code>new</code> على سبيل المثال - هذا الكائن لا ينتمي لقاعدة البيانات حتّى اللحظة. ما إن تقوم باستدعاء <code>save</code> لهذا الكائن سيتم حفظه في الجدول المناسب بقاعدة البيانات. يستخدم Active Record طريقة <code>?new_record</code> لتحديد إذا ما كان الكائن موجود في قاعدة البيانات أم لا. فكّر في فئة Active Record التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6568_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يمكننا ملاحظة أنها تعمل بالنظر إلى ناتج rails console:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6568_7" style="">
<code class="hljs coffeescript"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-built_in"><span class="pln">console</span></span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">new</span></span><span class="hljs-function"><span class="hljs-params"><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"John Doe"</span></span><span class="pun">)</span></span><span class="pln">
</span><span class="pun">=&gt;</span></span><span class="pln"> </span><span class="hljs-comment"><span class="com">#&lt;Person id: nil, name: "John Doe", created_at: nil, updated_at: nil&gt;</span></span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">new_record</span><span class="pun">?</span><span class="hljs-function"><span class="pln">
</span><span class="pun">=&gt;</span></span><span class="pln"> </span><span class="hljs-literal"><span class="kwd">true</span></span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">save</span><span class="hljs-function"><span class="pln">
</span><span class="pun">=&gt;</span></span><span class="pln"> </span><span class="hljs-literal"><span class="kwd">true</span></span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">new_record</span><span class="pun">?</span><span class="hljs-function"><span class="pln">
</span><span class="pun">=&gt;</span></span><span class="pln"> </span><span class="hljs-literal"><span class="kwd">false</span></span></code></pre>

<p>
	إن إنشاء و حفظ سجل جديد سوف يرسل عمليّة SQL INSERT إلى قاعدة البيانات. تحديث سجل موجود سوف يرسل عملية SQL UPDATE بدلًا من ذلك. التحقيقات تُجرى عادةً قبل إرسال هذه الأوامر إلى قاعدة البيانات. في حين فشل أي تحقيق سيتم تحديد الكائن “غير صالح” و لن ينفّذ Active Record عمليات الإدخال أو التحديث. يتجنّب هذا تخزين كائنات غير سارية في قاعدة البيانات. يمكنك أيضًا اختيار إجراء تحقيقات معينة عند إنشاء وحفظ أو تحديث كائن.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>تحذير</strong>: هناك طرق كثيرة لتغيير حالة الكائن في قاعدة البيانات. سوف تنشّط بعض الطرق التحقيقات، لكن بعضها لن يفعل ذلك. هذا يعني أنه من الممكن أن يتم حفظ كائن بقاعدة البيانات في حالة غير صالحة إذا لم تكن حذرًا.
		</p>
	</div>
</blockquote>

<p>
	الطرق التالية تُشغل التحقيقات و سوف تحفظ الكائنات في قاعدة البيانات فقط إذا كانت صالحة للاستخدام:
</p>

<ul>
<li>
		<code>create</code>
	</li>
	<li>
		<code>!create</code>
	</li>
	<li>
		<code>save</code>
	</li>
	<li>
		<code>!save</code>
	</li>
	<li>
		<code>update</code>
	</li>
	<li>
		<code>!update</code>
	</li>
</ul>
<p>
	الأوامر التى تنتهي بـ bang versions (مثل <code>!save</code> على سبيل المثال) تقوم بعمل استثناء فى حالة عدم صحة السجل. الآخرون لا يفعلون ذلك. <code>Save</code> و <code>update</code> يُخرجوا <code>false</code> خطأً ، و <code>create</code> تُعيد نفس الكائن.
</p>

<h3 id="13-تخطى-التحقيقات">
	1.3 تخطّى التحقيقات
</h3>

<p>
	الدوال التالية تتخطى التحقيقات و تحفظ الكائن فى قاعدة البيانات بغض النظر عن صحّته. لذلك يجب استخدامها بحذر.
</p>

<ul>
<li>
		<code>!decrement</code>
	</li>
	<li>
		<code>decrement_counter</code>
	</li>
	<li>
		<code>!increment</code>
	</li>
	<li>
		<code>increment_counter</code>
	</li>
	<li>
		<code>!toggle</code>
	</li>
	<li>
		<code>touch</code>
	</li>
	<li>
		<code>update_all</code>
	</li>
	<li>
		<code>update_attribute</code>
	</li>
	<li>
		<code>update_column</code>
	</li>
	<li>
		<code>update_columns</code>
	</li>
	<li>
		<code>update_counters</code>
	</li>
</ul>
<p>
	لاحظ أن save لديها القدرة على تخطي التحقيقات إذا تم إلحاقها بالأمر validate: false. هذه الطريقة أيضًا يجب استخدامها بحرص.
</p>

<ul>
<li>
		<code>(save(validate: false</code>
	</li>
</ul>
<h3 id="14-valid-و-invalid-صالح-و-غيرصالح">
	1.4 ?Valid و ?invalid  صالح؟ و غيرصالح؟
</h3>

<p>
	قبل حفظ كائن في Active Record، يجري Rails تحقيقاتك. لو كانت هذه التحقيقات تخرج أخطاء، لا يقوم Rails بحفظ الكائن. يمكنك أيضًا إجراء هذه التحقيقات بنفسك. <code>?Valid</code> ينشّط تحقيقاتك و يرد بـ <code>true</code> (صحيح) إذا لم يكن هناك أخطاء. و <code>false</code> (خطأ) فيما عدا ذلك. كما رأيت بالأعلى:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6568_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"John Doe"</span></span><span class="pun">).</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; true</span></span><span class="pln">
</span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">nil</span></span><span class="pun">).</span><span class="pln">valid</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; false</span></span></code></pre>

<p>
	بعد إجراء Active Record لتحقيقاتك، يمكن الوصول لأي خطأ من خلال وسيلة <code>errors.messages</code> التي ترد بمجموعة من الأخطاء. كما هي معرّفة، الكائن صالح للاستخدام إذا كان تجمع الأخطاء هذا فارغًا بعد إجراء التحقيقات. لاحظ أن الكائن الممثل بـ <code>new</code> لن يبلغ عن أخطاء حتى لو كان غير صالح تقنيًّا، لأن التحقيقات تُجرى تلقائيّا عندما يتم حفظ الكائن، كما هوالحال مع دوال <code>create</code> و <code>save</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6568_7" style="">
<code class="hljs avrasm"><span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  validates </span><span class="pun">:</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> presence</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="pun">&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">new</span></span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; #&lt;Person id: nil, name: nil&gt;</span></span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">errors</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">messages</span></span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; {}</span></span><span class="pln">

</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">valid</span></span><span class="pun">?</span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; false</span></span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">errors</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">messages</span></span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; {name:["can't be blank"]}</span></span><span class="pln">

</span><span class="pun">&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">create</span></span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; #&lt;Person id: nil, name: nil&gt;</span></span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">errors</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">messages</span></span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; {name:["can't be blank"]}</span></span><span class="pln">

</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">save</span></span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; false</span></span><span class="pln">

</span><span class="pun">&gt;&gt;</span><span class="pln"> p</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">save</span></span><span class="pun">!</span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; ActiveRecord::RecordInvalid: Validation failed: Name can't be blank</span></span><span class="pln">

</span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="typ">Person</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">create</span></span><span class="pun">!</span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># =&gt; ActiveRecord::RecordInvalid: Validation failed: Name can't be blank</span></span></code></pre>

<p>
	<code>?Invalid</code> هي ببساطة عكس <code>?valid</code>. تقوم بإجراء التحقيقات و ترد بـ <code>true</code> إذا وُجِدَ أي خطأ ، و <code>false</code> إذا لم تتواجد أيّة أخطاء.
</p>

<h3 id="15-errors-الأخطاء">
	1.5  [ ] errors الأخطاء
</h3>

<p>
	لكي تتأكد ما اذا كانت خاصّية معينة لكائن سارية أم لا يمكنك استخدام <code>[ errors [ :attribute</code>. تقوم بالرد بمصفوفة array بكل الأخطاء للخاصيّة. إذا لم يكن هناك أخطاء للخاصية المحددة يتم الرد بمصفوفة فارغة. تكون تلك الطريقة مفيدة بعدما تُجرى التحقيقات فقط، لأنها تقوم بفحص مجموعات الأخطاء فقط ولا تنشّط التحقيقات بنفسها. إنها تختلف عن طريقة <code>?ActiveRecord::Base#invalid</code> المشروحة بالأعلى، لأنها لا تؤكّد صحّة الكائن ككل. إنها تقوم فقط بفحص إذا وُجد أخطاء بخاصيّة واحدة بالكائن.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6568_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">].</span><span class="pln">any</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; false</span></span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">].</span><span class="pln">any</span><span class="pun">?</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; true</span></span></code></pre>

<h3 id="16-errorsdetails-تفاصيل-الأخطاء">
	1.6 errors.details تفاصيل الأخطاء
</h3>

<p>
	لكي تكشف أي تحقيقات فشلت في خاصية معيّنة يمكنك استخدام <code>[ errors.details [ :attribute</code> . تقوم بالرد بمصفوفة من الـ <code>hashes</code> مع مفتاح  <code>error:</code> للحصول على رمز المصادقة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6568_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Person</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="pun">&gt;&gt;</span><span class="pln"> person </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Person</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> person</span><span class="pun">.</span><span class="pln">valid</span><span class="pun">?</span><span class="pln">
</span><span class="pun">&gt;&gt;</span><span class="pln"> person</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">details</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">]</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; [{error: :blank}]</span></span></code></pre>

<p>
	المصدر:<br><a href="http://guides.rubyonrails.org/active_record_validations.html" rel="external nofollow">توثيقات Ruby on Rails</a>.
</p>
]]></description><guid isPermaLink="false">573</guid><pubDate>Tue, 12 Dec 2017 18:02:00 +0000</pubDate></item><item><title>Active Record Migration : &#x627;&#x644;&#x62A;&#x634;&#x63A;&#x64A;&#x644;&#x60C; &#x627;&#x644;&#x62A;&#x63A;&#x64A;&#x64A;&#x631; &#x648;&#x627;&#x644;&#x62A;&#x643;&#x627;&#x645;&#x644; &#x627;&#x644;&#x645;&#x631;&#x62C;&#x639;&#x64A;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-migration-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84%D8%8C-%D8%A7%D9%84%D8%AA%D8%BA%D9%8A%D9%8A%D8%B1-%D9%88%D8%A7%D9%84%D8%AA%D9%83%D8%A7%D9%85%D9%84-%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9%D9%8A-r569/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_12/5a26d8ac8fff1_05(1).png.da40fd372e049fd07e3800fb31c3ff45.png" /></p>

<p>
	في الدروس السابقة ألقينا <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-migrations-%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D9%88%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A6%D9%87-r563/" rel="">نظرة عامة على تهجير Active Record</a> وكيفية إنشائه كما وتعلمنا <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-migrations-%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%A7%D9%84%D8%AA%D9%87%D8%AC%D9%8A%D8%B1-r566/" rel="">أوامر التهجير</a> وسنتابع في هذا الدرس ما بقي من هذه السلسلة التعليمية حول تهجير Active Record.
</p>

<h2 id="4-تشغيل-التهجير-running-migration">
	4 تشغيل التهجير Running Migration
</h2>

<p>
	Rails توفر مجموعة من مهام bin/rails لتشغيل مجموعة التهجيرات التي تريدها. إن أول مهام التهجير bin/rails التي ستستعملها سيكون غالبًا <code>rails db:migrate</code>. و هذا هو أبسط صور التهجير حيث يقوم بتشغيل دوال <code>change</code> و <code>up</code> لكل التهجيرات التي لم تقم بتشغيلها بعد. و سيقوم بالإغلاق إن لم يُكن لديك تهجيرات من هذا النوع. عدا ذلك سيقوم بتشغيل التهجيرات بالترتيب طبقًا لتوقيته. لاحظ أن تشغيل أمر <code>db:migrate</code> سيقوم بتشغيل الأمر <code>db:schema:dump</code> و هذا سوف يقوم بتحديث ملف <code>db/schema.rb</code> ليوافق تركيب قاعدة بياناتك. إذا قُمت بتحديد نُسخة <code>version</code> معينة، فإن Active Record سيقوم بعمل التهجيرات اللازمة (باستخدام دوال <code>change</code> و <code>up</code> و <code>down</code>) حتى يصل للنسخة المرغوبة. يُعبر عن النسخة باستخدام أرقام توضع في إسم ملف التهجير، فإذا أردت أن تقوم بالتهجير لنُسخة 20080906120000 قُم بتشغيل:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails db</span><span class="pun">:</span><span class="pln">migrate VERSION</span><span class="pun">=</span><span class="lit">20080906120000</span></pre>

<p>
	إذا كانت النُسخة المرغوبة تحمل رقم أعلى من الرقم السابق فإن التهجير سيقوم بتشغيل دوال <code>change</code> أو <code>up</code>. و يقوم بعمل التهجيرات حتى يصل إلى رقم النُسخة المرغوبة. أما إذا كانت النسخة المرغوبة تحمل رقمًا أعلى فإن التهجير سيقوم بتشغيل دالة <code>down</code> حتى تصل إلى رقم النُسخة، لكنه لن يقوم بعمل تهجير لها(لأن ذلك سيؤدي إلى نُسخة أقل من المرغوبة).
</p>

<h3 id="41-العودة-للوراء-بإستخدام-rollback">
	4.1 العودة للوراء باستخدام rollback
</h3>

<p>
	سيتحتم عليك أحيانًا العودة بالتهجير للوراء (لاحظ الفرق بينه و بين العكس). مثال: إذا أردت أن تقوم بتصحيح خطأ قُمت به، فبدلًا من تتبع رقم النُسخة المرتبطة بذلك التهجير، يُمكنك تشغيل هذا الكود:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-symbol"><span class="pln">db</span><span class="pun">:</span></span><span class="pln">rollback</span></code></pre>

<p>
	إن أمر <code>rollback</code> سيقوم بعكس دالة <code>change</code> أو تشغيل دالة <code>down</code>. أما إذا أردت أن تعود لأكثر من تهجير يُمكنك تحديد عدد المرات التي ستعمل فيها الدالة <code>rollback</code> عن طريق STEP. مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs fix"><span class="hljs-attribute"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails db</span><span class="pun">:</span><span class="pln">rollback STEP</span></span><span class="pun">=</span><span class="hljs-string"><span class="lit">3</span></span></code></pre>

<p>
	هذا سوف يعكس 3 تهجيرات. إن أمر <code>db:migrate:redo</code> يُعتبر إختصار لأمر <code>rollback</code> و لكنه سيعود بك لنقطة البداية مُجددًا. و يُمكنك تعيين عدد الخطوات به أيضًا باستخدام STEP، مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-symbol"><span class="pln">db</span><span class="pun">:</span></span><span class="hljs-symbol"><span class="pln">migrate</span><span class="pun">:</span></span><span class="hljs-keyword"><span class="kwd">redo</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">STEP</span></span><span class="pun">=</span><span class="hljs-number"><span class="lit">3</span></span></code></pre>

<p>
	إن دالة <code>db:migrate</code> يُمكنها أي شيئ تقوم به أوامر bin/rails ولكنهم أكثر مُلائمة عندما لا تحتاج لتحديد النُسخة التي تعمل عليها بدقة.
</p>

<h3 id="42-تهيئة-قاعدة-البيانات-setup-database">
	4.2 تهيئة قاعدة البيانات Setup Database
</h3>

<p>
	أمر <code>rails db:setup</code> سيقوم بصنع قاعدة البيانات و تحميل الإسكيما و تزويدها ببياناتها الأولية.
</p>

<h3 id="43-إعادة-تهيئة-قاعدة-البيانات-resetting-database">
	4.3 إعادة تهيئة قاعدة البيانات Resetting Database
</h3>

<p>
	لإعادة التهيئة استخدم أمر <code>rails db:reset</code> ثم قُم باستعمال أمر التهيئة من جديد. و هذان الأمران يُمكن استبدالهما بدالة <code>rails db:drop db:setup</code>
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			لاحظ أن هذا الأمر مُختلف عن تشغيل التهجيرات كُلها مرة واحدة. حيث سيقوم باستعمال الملف الحالي سواء كان <code>db/schema.rb</code> أو <code>db/structre.sql</code> أما إذا كان التهجير لا يُمكن تطبيق دالة العودة <code>rollback</code> عليه، فلن يُمكنك إستخدام أمر <code>rails db:reset</code>
		</p>
	</div>
</blockquote>

<h3 id="44-تشغيل-تهجيرات-محددة-running-specific-migrations">
	4.4 تشغيل تهجيرات محددة Running Specific Migrations
</h3>

<p>
	إذا كُنت تريد إجراء عملية تهجير محددة سواء للأمام <code>up</code> أو للخلف <code>down</code>. فيُمكنك إستخدام أمر <code>db:migrate:up</code> أو <code>db:migrate:down</code> و لكن سيتوجب عليك تحديد تعيين رقم نُسخة التهجير الذي ترغب بعمله، مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs fix"><span class="hljs-attribute"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails db</span><span class="pun">:</span><span class="pln">migrate</span><span class="pun">:</span><span class="pln">up VERSION</span></span><span class="pun">=</span><span class="hljs-string"><span class="lit">20080906120000</span></span></code></pre>

<p>
	في المثال السابق سيقوم Active Record بالتأكد من وجود هذا التهجير مُسبقًا أم لا. فإن لم يكن موجودًا من قبل فسيقوم بتشغيل دالة <code>change</code> أو دالة <code>up</code>. أما إذا كان موجودًا بالفعل فلن يقوم بشيء.
</p>

<h3 id="45-تشغيل-التهجير-في-بيئات-عمل-مختلفة-different-environments">
	4.5 تشغيل التهجير في بيئات عمل مختلفة different environments
</h3>

<p>
	تلقائيًا يتم تشغيل <code>bin/rails db:migrate</code> في بيئة development. ويُمكنك استعمال هذا الأمر <code>RAILS_ENV</code> لتحديد بيئة العمل التي ترغب بعمل التهجير عليها، في الكود التالي سنقوم بعمل التهجيرات على بيئة test:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs fix"><span class="hljs-attribute"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails db</span><span class="pun">:</span><span class="pln">migrate RAILS_ENV</span></span><span class="pun">=</span><span class="hljs-string"><span class="pln">test</span></span></code></pre>

<h3 id="46-تغيير-ناتج-خارج-output-التهجير">
	4.6 تغيير ناتج (خارج – Output) التهجير
</h3>

<p>
	إن التهجير تلقائيًا يقوم بإخبارك بالمهام التي يفعلها و الوقت الذي قد يأخذه، فإذا قُمت باستخدام تهجير لصنع جدول أو إضافة قاموس، فإن الناتج سيكون هكذا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs asciidoc"><span class="hljs-header"><span class="pun">==</span><span class="pln">  </span><span class="typ">CreateProducts</span><span class="pun">:</span><span class="pln"> migrating </span><span class="pun">=================================================</span></span><span class="pln">
</span><span class="hljs-bullet"><span class="pun">--</span><span class="pln"> </span></span><span class="pln">create</span><span class="hljs-emphasis"><span class="pln">_table</span><span class="pun">(:</span><span class="pln">products</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">0.0028s</span><span class="pln">
</span><span class="pun">==</span><span class="pln">  </span><span class="typ">CreateProducts</span><span class="pun">:</span><span class="pln"> migrated </span><span class="pun">(</span><span class="lit">0.0028s</span><span class="pun">)</span><span class="pln"> </span><span class="pun">========================================</span></span></code></pre>

<p>
	و هُناك العديد من الدوال المتوفرة داخل ملفات التهجير تساعد بمعرفة هذا الأمر:
</p>

<center>
	<table border="1"><tbody>
<tr>
<td style="background-color: rgb(255,55,55); color: rgb(255,255,255); padding: 5px 10px; text-align: center;">
					الدالة
				</td>
				<td style="background-color: rgb(255,55,55); color: rgb(255,255,255); padding: 5px 10px; text-align: center;">
					غرضها
				</td>
			</tr>
<tr>
<td style="padding: 5px 10px; text-align: left;">
					<code>suppress_message</code>
				</td>
				<td style="padding: 5px 10px;">
					يقوم بتحديد جزء من الكود block و يقوم بإخراج رسالة تحتوي على ما بهذا الكود.
				</td>
			</tr>
<tr>
<td style="padding: 5px 10px; text-align: left;">
					<code>say</code>
				</td>
				<td style="padding: 5px 10px;">
					يقوم هذا الأمر بحفظ نص رسالة و تقديمها كما هي. و سيقوم مُتغير من نوع Boolean بتحديد ظهور الرسالة من عدمه
				</td>
			</tr>
<tr>
<td style="padding: 5px 10px; text-align: left;">
					<code>say_with_time</code>
				</td>
				<td style="padding: 5px 10px;">
					يقوم بتحديد وقت مُعين لظهور الرسالة، و إذا كان الكود المكتوب يُخرج رقم integer فإنه يُعامله على أنه عدد الصفوف المُتأثرة.
				</td>
			</tr>
</tbody></table>
</center>

<p>
	على سبيل المثال، فإن هذا التهجير:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CreateProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    suppress_messages </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
      create_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
        t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pln">
        t</span><span class="pun">.</span><span class="pln">text </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">description</span></span><span class="pln">
        t</span><span class="pun">.</span><span class="pln">timestamps
      </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

    say </span><span class="hljs-string"><span class="str">"Created a table"</span></span><span class="pln">

    suppress_messages </span><span class="pun">{</span><span class="pln">add_index </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">}</span><span class="pln">
    say </span><span class="hljs-string"><span class="str">"and an index!"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">

    say_with_time </span><span class="hljs-string"><span class="str">'Waiting for a while'</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
      sleep </span><span class="hljs-number"><span class="lit">10</span></span><span class="pln">
      </span><span class="hljs-number"><span class="lit">250</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	سوف يُنتج هذه المُخرجات
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs asciidoc"><span class="hljs-header"><span class="pun">==</span><span class="pln">  </span><span class="typ">CreateProducts</span><span class="pun">:</span><span class="pln"> migrating </span><span class="pun">=================================================</span></span><span class="pln">
</span><span class="hljs-bullet"><span class="pun">--</span><span class="pln"> </span></span><span class="typ">Created</span><span class="pln"> a table
</span><span class="hljs-code"><span class="pln">   </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> an index</span><span class="pun">!</span></span><span class="pln">
</span><span class="hljs-bullet"><span class="pun">--</span><span class="pln"> </span></span><span class="typ">Waiting</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> a </span><span class="kwd">while</span><span class="pln">
</span><span class="hljs-code"><span class="pln">   </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">10.0013s</span></span><span class="pln">
</span><span class="hljs-code"><span class="pln">   </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">250</span><span class="pln"> rows</span></span><span class="pln">
</span><span class="hljs-header"><span class="pun">==</span><span class="pln">  </span><span class="typ">CreateProducts</span><span class="pun">:</span><span class="pln"> migrated </span><span class="pun">(</span><span class="lit">10.0054s</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=======================================</span></span></code></pre>

<p>
	أما إذا أردت من Active Record ألا يُخرج أي شيئ فيُمكنك استخدام أمر <code>rails db:migrate VERBOSE=false</code>
</p>

<h2 id="5-تغيير-التهجيرات-الموجودة-مسبقا">
	5 تغيير التهجيرات الموجودة مُسبقًا
</h2>

<p>
	إذا قُمت بارتكاب خطأ ما أثناء كتابتك للتهجير، و قُمت بتشغيل التهجير. فلا يُمكنك تعديل التهجير ثًم تشغيله من جديد. لأن Rails لن تفعل شيئًا عند كتابة الأمر <code>rails eb:migrate</code> لأنك بالفعل قُمت بتشغيله من قبل. لذلك عليك استخدام أمر العودة <code>rollback</code> بكتابة <code>bin/rails db:rollback</code> ثُم تعديل التهجير ثُم تشغيله من جديد. بوجه عام، تعديل التهجيرات السابقة ليس أمرًا جيدًا، لأنه سيتسبب لك بالكثير من العمل، أنت و من يعملون معك على قاعدة البيانات. خصيصًا إن تم تشغيل هذا التهجير على أجهزة السيرفرات بالفعل. فبدلًا من عمل ذلك يُمكنك كتابة تهجير جديد وظيفته هي تغيير الأخطاء أو عمل التعديلات اللازمة. فإن تعديل تهجير مكتوب حديثًا أسهل من تعديل تهجير تم تشغيله على الأجهزة فعلًا. يُمكنك إستخدام أمر العاكس revert الذي تحدثنا عنه هُنا مُسبقًا.
</p>

<h2 id="6-إهمال-الإسكيما-schema-dumping">
	6 إهمال الإسكيما Schema Dumping
</h2>

<h3 id="61-ماهي-ملفات-الإسكيما">
	6.1 ماهي ملفات الإسكيما؟
</h3>

<p>
	إن التهجيرات، ليست هي المُتحكمة بالإسكيما الخاصة بقاعدة بياناتك. إن هذا الأمر (التحكم) يعود إلى ملفات <code>db/schema.rb</code> أو ملف SQL. و تلك الملفات تولد من Active Record عن طريق مُعاينة قاعدة البيانات. وإن تلك الملفات ليست مُصممة ليتم التعديل عليها، بل هي تُظهر و تُمثل حالة قاعدة البيانات. ليس هُناك حاجة لعمل جزئية جديدة بتطبيقٍ ما عن طريق إعادة تشغيل جميع التهجيرات بالتطبيق. فإنه من الأسهل و الأسرع إضافة وصف تلك الجزئية للإسكيما الحالية لقاعدة البيانات. هكذا تكون قاعدة البيانات الإختبارية على سبيل المثال، بحيث يتم إهمال الملفات الحالية لقاعدة البيانات (ملف <code>db/schema.rb</code> و <code>db/structre.sql</code>) و يتم تحميلها إلى قاعدة البيانات الإختبارية test database. إن ملفات الإسكيما مُفيدة أيضًا إذا أردت أن تلقي نظرة سريعة إلى الخصائص التي تحملها كائنات Active Record. حيث أن هذه المعلومات لا توجد في كود نموذج قاعدة البيانات و أحيانًا تكون مُنتشرة بين العديد من التهجيرات، لكن المعلومات تكون جميعها موجود في ملفات الإسكيما بشكل مُنظم.
</p>

<h3 id="62-أنواع-إهمال-الإسكيما-schema-dumps">
	6.2 أنواع إهمال الإسكيما schema dumps
</h3>

<p>
	هُناك طريقتين أساسيتين لهجر/إهمال إسكيما ما. هذا يكون موجودًا داخل ملف <code>config/application.rb</code> عن طريق إعداد <code>config.active_record.schema_format</code>، و من المُمكن أن يكون ملف روبي <code>ruby:</code> أو  <code>sql:</code><br>
	إذا كان من نوع روبي <code>ruby:</code> فإنه سيبدو مثل تهجير كبير، و ستجده داخل <code>db/schema.rb</code>، مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs livecodeserver"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Schema</span><span class="pun">.</span><span class="pln">define</span><span class="pun">(</span><span class="hljs-built_in"><span class="pln">version</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">20080906171750</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">do</span></span><span class="pln">
  create_table </span><span class="hljs-string"><span class="str">"authors"</span></span><span class="pun">,</span><span class="pln"> force</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">true</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
    t</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pln">   </span><span class="hljs-string"><span class="str">"name"</span></span><span class="pln">
    t</span><span class="pun">.</span><span class="pln">datetime </span><span class="hljs-string"><span class="str">"created_at"</span></span><span class="pln">
    t</span><span class="pun">.</span><span class="pln">datetime </span><span class="hljs-string"><span class="str">"updated_at"</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">end</span></span></span><span class="pln">

  create_table </span><span class="hljs-string"><span class="str">"products"</span></span><span class="pun">,</span><span class="pln"> force</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">true</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
    t</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pln">   </span><span class="hljs-string"><span class="str">"name"</span></span><span class="pln">
    t</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">text</span></span><span class="pln">     </span><span class="hljs-string"><span class="str">"description"</span></span><span class="pln">
    t</span><span class="pun">.</span><span class="pln">datetime </span><span class="hljs-string"><span class="str">"created_at"</span></span><span class="pln">
    t</span><span class="pun">.</span><span class="pln">datetime </span><span class="hljs-string"><span class="str">"updated_at"</span></span><span class="pln">
    t</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pln">   </span><span class="hljs-string"><span class="str">"part_number"</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">end</span></span></span><span class="pln">
</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">end</span></span></span></code></pre>

<p>
	في كثير من الحالات، يتم صُنع هذه الملفات عن طريق مُعاينة قاعدة البيانات و تركيبها باستعمال الدوال المُستخدمة بصُنعها مثل <code>create_table</code> و <code>add-Index</code> و غيرهم. و لأن هذا أمر يكون مُستقل بقاعدة البيانات، فيُمكن استخدامها على أي قاعدة بيانات يدعمها Active Record. ومن فوائد هذا الأمر، أنه يُمكنك توزيع بيانات تطبيق ما على العديد من قواعد البيانات. من سلبيات ملف الإسكيما <code>db/schema.rb</code> أنه لا يُمكنك التعبير عن جميع مُكونات قاعدة البيانات مثل: المُشغلات/مُنشطات triggers و نقاط التحقق check constraints. بينما في التهجير يُمكنك الإستعانة بسطور  SQL. و الإسكيما لا يُمكنها أن تحتوي على تلك السطور. لذلك إن إحتوت قاعدتك بيانات على مثل هذه الخصائص، فيجب عليك تحويل صيغة ملف الإسكيما إلى <code>sql:</code>.<br>
	بدلًا من إهمال استعمال إسكيما Active Record، فإنه يُمكنك إهمال تركيب/تخطيط قاعدة البيانات بإستخدام أدوات مُعينة مثل (أمر <code>rails db:structre:dump</code> ) في ملف <code>db/structre.sql</code>. على سبيل المثال: في قواعد بيانات من نوع PostgreSQL يُمكنك إستخدام <code>pg_dump</code>. أما في قواعد بيانات MySQL و MariaDB فإن الملف سيظهر لك SHOW CREATE TABLE لمُختلف الجداول التي يحويها هذا الملف.
</p>

<h3 id="63-إهمال-الإسكيما-و-التحكم-بالكود-المصدري-source-control">
	6.3 إهمال الإسكيما و التحكم بالكود المصدري source control
</h3>

<p>
	لأن أوامر إهمال الإسكيما هي المُنحكم الرئيسي بالإسكيما الخاصة بقاعدة البيانات. لذلك يُنصح بشدة بأن تتأكد من وجودهم بلوحة تحكم المصدر الخاصة بك. إن ملف <code>db/schema.rb</code> يحتوي على النُسخة الحالية من قاعدة البيانات الخاصة بك. هذا يؤكد حدوث الأخطاء عند دمج العديد منها. و حل هذا الأخطاء يكون يدويًا بإبقاء النُسخة الأعلى من المدمجين.
</p>

<h2 id="7-active-record-و-التكامل-المرجعي-referential-integrity">
	7 Active Record و التكامل المرجعي referential integrity
</h2>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			التكامل المرجعي: هو دمج العديد من قواعد البيانات معًا.
		</p>
	</div>
</blockquote>

<p>
	إن Active Record يدعي أن هُناك آلية ذكية في النماذج الخاصة بقواعد البيانات و ليس بقواعد البيانات نفسها. مثل المميزات triggers و constraints التي تضيف هذه الآلية إلى قاعدة البيانات نفسها, و لكنها ليست مُستخدمة بكثرة. التحقيقات مثل <code>validates:foreign_key</code> و <code>uniqueness: true</code> هي التي تُستخدم عن تكامل البيانات بين قواعد البيانات. فأمر <code>dependent:</code> في القواعد المُتصلة يسمح بتدمير الكائن المورَث عند تدمير الكائن المورِث. هذا لا يُمكن ضمان حدوثه في التكامل المرجعي بوجود تحقيقات المفاتيح الأجنبية في قاعدة البيانات. و مع ذلك فإن Active Record لا يوفر جميع الأدوات التي تعمل مُباشرةً مع هذه المميزات، لذلك فإنه يُمكنك إستخدام أمر excute لتنفيذ أوامر SQL.
</p>

<h2 id="8-التهجير-و-البيانات-المرجعية-seed-data">
	8 التهجير و البيانات المرجعية seed data
</h2>

<p>
	حتى لا ننسى أن الهدف الأساسي من خاصية التهجير و هو عمل أوامر تُعدل على الإسكيما بإستخدام أوامر ثابتة و مُتسقة. إن التهجير أيضًا يُمكن إستعماله لإضافة أو تعديل البيانات، و هذا مُفيد في قواعد البيانات الموجودة مُسبقًا التي لا يُمكن تدميرها و إعادة صُنعها. مثل تلك قاعدة البيانات الخاصة بالإنتاج:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">AddInitialProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">up
    </span><span class="hljs-number"><span class="lit">5</span></span><span class="lit">.times</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">i</span><span class="pun">|</span><span class="pln">
      </span><span class="hljs-constant"><span class="typ">Product</span></span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"Product #</span><span class="hljs-subst"><span class="str">#{i}</span></span><span class="str">"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">description</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"A product."</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">down
    </span><span class="hljs-constant"><span class="typ">Product</span></span><span class="pun">.</span><span class="pln">delete_all
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	لإضاافة بيانات أولية seed data بعد صُنع قاعدة البيانات. إن Rails لديها دالة داخلية built-in تُساعد على تسهيل تلك العملية. خصيصًا عند إعادة تحميل قواعد البيانات بشكل مُتكرر أثناء التطوير و الإختبار. يُمكنك إستخدام تلك الخاصية بكتابة أكواد ruby التي تريدها في ملف <code>db/seeds.rb</code> ثُم تشغيل أمر <code>rails db:seed</code>
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5494_8" style="">
<code class="hljs sql"><span class="lit">5.times</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">i</span><span class="pun">|</span><span class="pln">
  </span><span class="typ">Product</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">create</span></span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Product ##{i}"</span></span><span class="pun">,</span><span class="pln"> description</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"A product."</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-keyword"><span class="typ">End</span></span></span></code></pre>

<p>
	و يُمكنك إستخدام تلك الخاصية لإعداد قاعدة بيانات فارغة من البداية.<br>
	وبذلك نكون قد أنهينا هذه السلسلة المخصصة لتعلّم تهجير Active Record في إطار العمل روبي أون ريلز.
</p>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/active_record_migrations.html" rel="external nofollow">Ruby on Rails</a>.
</p>
]]></description><guid isPermaLink="false">569</guid><pubDate>Tue, 05 Dec 2017 17:34:00 +0000</pubDate></item><item><title>Active Record Migrations: &#x623;&#x648;&#x627;&#x645;&#x631; &#x627;&#x644;&#x62A;&#x647;&#x62C;&#x64A;&#x631;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-migrations-%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%A7%D9%84%D8%AA%D9%87%D8%AC%D9%8A%D8%B1-r566/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_11/5a1d469cc6ff8_28(1).png.165e3bb8df824f4f5ebc99d3eda68d34.png" /></p>

<p>
	في <a href="https://academy.hsoub.com/programming/ruby/rails/active-record-migrations-%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D9%88%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A6%D9%87-r563/" rel="">الدرس السابق</a> ألقينا نظرة عامة على تهجير Active Record وكيفية إنشائه وسنتابع في هذا الدرس تعلّم كيفية كتابة أوامره عبر صنع الجداول وتعديلها وغيرها.
</p>

<h2 id="3-كتابة-أوامر-التهجير">
	3 كتابة أوامر التهجير
</h2>

<p>
	بمجرد استخدامك للمولدات لتوليد التهجير، فسيتحتم عليك البدء بالعمل الحقيقي و كتابة أوامر التهجير.
</p>

<h3 id="31-صنع-الجداول">
	3.1 صُنع الجداول
</h3>

<p>
	إن دالة <code>create_tables</code> هي الأساسية لصنع الجداول، و لكن في مُعظم الأوقات ستقوم المولدات بإنتاج تلك الجداول كما رأينا في الأمثلة السابقة. مثال على صُنع جدول
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<span class="pln">create_table </span><span class="pun">:</span><span class="pln">products </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
  t</span><span class="pun">.</span><span class="pln">string </span><span class="pun">:</span><span class="pln">name
</span><span class="kwd">end</span></pre>

<p>
	وهذا سوف يصنع جدول يُسمى products يحتوي على عامود نصي يُسمى name (وعامود مُفتاح رئيسي يُسمى id يتولد تلقائيًا كما ناقشنا من قبل) و تلقائيًا، ستنتج دالة <code>create_table</code> ستصنع عامود مُفتاح رئيسي id. يُمكنك تغيير إسم هذا المُفتاح باستخدام أمر <code>primary_key:</code> (ولا تنسَ أن تقوم بهذا التغيير في بقية النماذج models)، كما يُمكنك إلغاء وجود ذلك المُفتاح إن لم تحتاجه بإستخدام أمر <code>id: false</code>. أما إذا أردت تعديل تخطي بعض الخيارات الأخرى لقاعدة البيانات، فيُمكنك استخدام سطور SQL في خيار <code>options:</code> وعلى سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_8" style="">
<span class="pln">create_table </span><span class="pun">:</span><span class="pln">products</span><span class="pun">,</span><span class="pln"> options</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ENGINE=BLACKHOLE"</span><span class="pln"> </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
  t</span><span class="pun">.</span><span class="pln">string </span><span class="pun">:</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> null</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	وهذا الكود سوف يُضيف <code>ENGINE = BLACKHOLE</code> إلى سطور SQL المسؤولة عن صُنع الجداول ( وفي حالة استعمال MySQL أو MariaDB، فإن الكود المُستخدم هو <code>ENGINE = InnoDB</code>). يُمكنك تعدي خيار <code>comment:</code> باستخدام أي وصف للجدول مُخزن في قاعدة البيانات نفسها و سيتم ظهور هذا الوصف أدوات إدارة قاعدة البيانات، مثل MySQL Workbench أو PgAdmin III. كما أنه من المُفضل لتوضيح التعليقات comments في التهجيرات المُستخدمة بتطبيقات قواعد البيانات الكبيرة. حيث سُتساعد من يقرأ قاعدة البيانات لفهم نماذج البيانات و عمل التوثيقات اللازمة لقاعدة البيانات.
</p>

<h3 id="32-صنع-الجداول-المدمجة">
	3.2 صُنع الجداول المُدمجة
</h3>

<p>
	إن دالة التهجير <code>creat_join_table</code> تقوم بصُنع جداول مُدمجة (HABTM-has and belongs to many) و التي كما عرفناها سابقًا عبارة عن عدة عواميد من جدول واحد أو جداول مُختلفة. مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="pln">create_join_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">categories</span></span></code></pre>

<p>
	و هذا سوف يصنع جدول <code>categories_products</code> يحتوي على عامودين يُسميان <code>category_id</code> و <code>product_id</code>. وهذه العواميد تلقائيًا تُعطي قيمة <code>false</code> للأمر <code>null:</code> و يُمكن تخطي هذا الأمر بالتعديل على الخيار <code>column_options:</code>، مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">create_join_table</span></span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">categories</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">column_options</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="kwd">null</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span></span></span></span><span class="pun">}</span></code></pre>

<p>
	إسم الجدول المُدمج سيتكون من إسم العواميد المكونة له طبقًا لترتيبها الأبجدي، و لتغير ذلك يُمكنك إستخدام قواعد التسمية المُستخدمة في المقال السابق و بدالة <code>table_name:</code>، مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="pln">create_join_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">categories</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">table_name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">categorization</span></span></code></pre>

<p>
	مما سينتج عن الكود السابق جدول يُسمى categorization. كما أن دالة <code>create_join_table</code> يُمكنها إضافة الفهارس و العواميد الإضافية (و لا يتم عمل ذلك بشكل تلقائي إذ يجب عليك تحديد الفهارس أو العواميد الإضافية) مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="pln">create_join_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">categories</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
  t</span><span class="pun">.</span><span class="pln">index </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">product_id</span></span><span class="pln">
  t</span><span class="pun">.</span><span class="pln">index </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">category_id</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<h3 id="33-تغيير-الجداول">
	3.3 تغيير الجداول
</h3>

<p>
	إن دالة تغيير الجداول <code>change_table</code> مُشابهة لدالة صُنعها <code>create_table</code> عدا أن الثانية تُستخدم لتغير جداول موجودة مُسبقًا. و تعمل بنفس الطريقة و لكنك لن تحتاج إعادة تعريف كُل شيئ لأنه سيأخُذها من الجدول المُتغير منه. مثال على ذلك:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="pln">change_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
  t</span><span class="pun">.</span><span class="pln">remove </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">description</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pln">
  t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pln">
  t</span><span class="pun">.</span><span class="pln">index </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pln">
  t</span><span class="pun">.</span><span class="pln">rename </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">upccode</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">upc_code</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	الكود السابق سوف يحذف العواميد <code>description</code> و <code>columns</code>. و سيصنع عامود نصي <code>part_number</code> وسيضيف فهرس إليه، و سيقوم أيضًا بإعادة تسمية عامود <code>upccode</code>.
</p>

<h3 id="34-تغيير-الأعمدة">
	3.4 تغيير الأعمدة
</h3>

<p>
	توفر Rails أمر التهجير <code>change_column</code> و الذي يؤدي دور الأوامر <code>remove_column</code> و <code>add_column</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="pln">change_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">text</span></span></code></pre>

<p>
	الكود أعلاه سيُغير نوع العامود <code>part_number</code> في الجدول products ليُصبح حقل نصوص texts. لاحظ أن الدالة <code>change_column</code> لا يُمكن عكسها. وبجانب دالة <code>change_column</code> يوجد دوال <code>change_column_null</code> و <code>change_column_default</code> التي تُستخدم تحديدًا لتغيير القيم الإفتراضية <code>default values</code> للعامود.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="pln">change_column_null </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">false</span></span><span class="pln">
change_column_default </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">approved</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="kwd">from</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">to</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">false</span></span></code></pre>

<p>
	الكود أعلاه سيقوم بتغيير الحقل <code>name:</code> في جدول <code>products</code> ليُصبح من نوع <code>NOT NULL</code> و القيمة الإفتراضية لحقل <code>approved:</code> من <code>true</code> إلى <code>false</code>.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>مُلاخظة</strong>: يُوجد طريقة أخرى لكتابة أمر التهجير <code>change_column_default</code> و هي <code>change_column_default :products, :approved, false</code> و لكن هذه الطريقة لا يُمكن عكسها <code>irreversible</code> عكس المُستخدمة في الكود أعلاه.
		</p>
	</div>
</blockquote>

<h3 id="35-معدلات-الأعمدة">
	3.5 مُعدلات الأعمدة
</h3>

<p>
	إن مُعدلات الأعمدة Column Modifiers يُمكن أن تُطبق عند صُنع أو تغيير العواميد:
</p>

<ul>
<li>
		<code>limit</code> : يقوم بتحديد أقصى مساحة للحقول من الأنواع <code>string/text/binary/integer</code>
	</li>
	<li>
		<code>Precision :</code> يُحدد دقة الأرقام العشرية بتحديد عدد الوحدات في الرقم الواحد قبل العلامة العشرية
	</li>
	<li>
		<code>Scale</code> : يُحدد دقة الأرقام العشرية بتحديد عدد الوحدات في الرقم الواحد بعد العلامة العشرية
	</li>
	<li>
		<code>Polymorphic</code> : يُضيف عامود <code>type</code> إلى رابطة <code>belong_to</code>
	</li>
	<li>
		<code>Null</code> : تسمح بإستخدام قيمة <code>NULL</code> أو عدم إستخدامها بالعامود.
	</li>
	<li>
		<code>Default</code> : يُتيح لك بتعيين قيمة إفتراضية بالعامود. مع مُلاحظة أنه عند إستخدامك قيمة ديناميكية (مثل التاريخ، فإنه سيتم تعيين القيمة الإفتراضية للتاريخ الذي تم صُنع التهجير عنده.
	</li>
	<li>
		<code>Index</code> : يُضيف فهرس للعامود
	</li>
	<li>
		<code>Comment</code> : يُضيف تعليق للعامود
	</li>
</ul>
<p>
	بعض المحولات <code>adapters</code> تدعم بعض الخيارات الإضافية: يُمكنك رؤية التوثيقات الخاصة بتلك المحولات لمعرفة المزيد عن هذا الأمر.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			**لاحظ أنه أمري <code>null</code> و <code>support</code> لا يُمكن تحديدهم بإستخدام واجهة الأوامر Command Line
		</p>
	</div>
</blockquote>

<h3 id="36-المفاتيح-الأجنبية">
	3.6 المفاتيح الأجنبية
</h3>

<p>
	على الرغم من عدم إضطرارك لإضافة المفاتيح الأجنبية Foreign Keys إلا أنه يُمكنك فعل ذلك لضمان السلامة المرجعية لقاعدة البيانات.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="pln">add_foreign_key </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">articles</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">authors</span></span></code></pre>

<p>
	هذا سوف يُضيف مفتاح أجنبي جديد إلى عامود <code>author_id</code> في جدول <code>articles</code>. والمفتاح سيرمز إلى عامود <code>id</code> في جدول <code>authors</code>. أما إذا كانت أسماء الأعمدة لا يُمكن إشتقاقها من أسماء الجداول، فيُمكنك إستخدام الأوامر <code>column:</code> و <code>primary_key:</code>. إن Rails أيضًا ستقوم بتوليد إسم إفتراضي لكُل مُفتاح أجنبي، سيبدأ بـ <code>fk_rails_</code> ثُم سيُتبع بعشرة حروف التي ستتولد تلقائيًا من أمر <code>from_table</code> و <code>column</code>. و يُمكنك أيضًا إستخدام <code>name:</code> لتعيين إسم مُختلف إذا أردت.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			**ملحوظة: إن Active Record يدعم عامود واحد من المفاتيح الأجنبية foreign keys. عدا ذلك يُمكنك إستخدام ملف <code>excute.sql</code> أو <code>structre.sql</code> لإستخدام العديد منها.
		</p>
	</div>
</blockquote>

<p>
	حذف المفاتيح الأجنبية لهو أمر سهل أيضًا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="hljs-comment"><span class="com"># let Active Record figure out the column name</span></span><span class="pln">
remove_foreign_key </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">accounts</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">branches</span></span><span class="pln">

</span><span class="hljs-comment"><span class="com"># remove foreign key for a specific column</span></span><span class="pln">
remove_foreign_key </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">accounts</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">column</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">owner_id</span></span><span class="pln">

</span><span class="hljs-comment"><span class="com"># remove foreign key by name</span></span><span class="pln">
remove_foreign_key </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">accounts</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">special_fk_name</span></span></code></pre>

<h3 id="37-إستخدام-دالة-التغيير-change">
	3.7 إستخدام دالة التغيير change
</h3>

<p>
	إن دالة التغيير <code>change</code> هي الطريقة الأساسية لكتابة أوامر التهجير (حيث كما علمنا فإن التهجير هو عبارة عن تغيير في الأساس). و في أغلب الحالات، فإن Active Record يُمكنه عكس تلك التهجيرات. حاليًا، يُمكنك إستخدام دالة التغيير على الدوال الآتية:
</p>

<ul>
<li>
		<code>add_column</code>
	</li>
	<li>
		<code>add_foreign_key</code>
	</li>
	<li>
		<code>add_index</code>
	</li>
	<li>
		<code>add_reference</code>
	</li>
	<li>
		<code>add_timestamps</code>
	</li>
	<li>
		<code>change_column_default (must supply a :from and :to option)</code>
	</li>
	<li>
		<code>change_column_null</code>
	</li>
	<li>
		<code>create_join_table</code>
	</li>
	<li>
		<code>create_table</code>
	</li>
	<li>
		<code>disable_extension</code>
	</li>
	<li>
		<code>drop_join_table</code>
	</li>
	<li>
		<code>drop_table (must supply a block)</code>
	</li>
	<li>
		<code>enable_extension</code>
	</li>
	<li>
		<code>remove_column (must supply a type)</code>
	</li>
	<li>
		<code>remove_foreign_key (must supply a second table)</code>
	</li>
	<li>
		<code>remove_index</code>
	</li>
	<li>
		<code>remove_reference</code>
	</li>
	<li>
		<code>remove_timestamps</code>
	</li>
	<li>
		<code>rename_column</code>
	</li>
	<li>
		<code>rename_index</code>
	</li>
	<li>
		<code>rename_table</code>
	</li>
</ul>
<p>
	دالة <code>change_table</code> يُمكن عكسها في حالة أن الجدول لا يقوم بإستدعاء دالة <code>change</code> أو <code>change_default</code> أو <code>remove</code>. ودالة <code>remove_column</code> أيضًا يُمكن عكسها إذا قُمت بتوفير نوع العامود كعامل ثالث موفرًا أيضًا باقي خيارات العامود. وبدون ذلك فإن Rails لن تتمكن من عمل العامود عند إستخدام الأوامر العكسية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs cs"><span class="pln">remove_column </span><span class="pun">:</span><span class="pln">posts</span><span class="pun">,</span><span class="pln"> </span><span class="pun">:</span><span class="pln">slug</span><span class="pun">,</span><span class="pln"> </span><span class="pun">:</span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">null</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">false</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">default</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">''</span></span><span class="pun">,</span><span class="pln"> index</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span></code></pre>

<p>
	أما إذا أُضطررت لإستعمال دوال أخرى فعليك إستعمال أمر <code>reversible</code> أو كتابة أوامر <code>up</code> و <code>down</code> بدلًا من إستعمال دالة <code>change</code>.
</p>

<h3 id="39-إستعمال-أمر-العكس-reversible">
	3.9 إستعمال أمر العكس reversible
</h3>

<p>
	إن التهجيرات المُعقدة تتطلب مُعالجة لا يستطيع Active Record عكسها. لذلك يُمكنك إستخدام أمر <code>reversible</code> لتحديد ماذا يحدث عند تشغيل التهجير و ماذا يحدث عند عكسه، مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">ExampleMigration</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    create_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">distributors</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">zipcode</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

    reversible </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">dir</span><span class="pun">|</span><span class="pln">
      dir</span><span class="pun">.</span><span class="pln">up </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
        </span><span class="hljs-comment"><span class="com"># add a CHECK constraint</span></span><span class="pln">
        execute </span><span class="pun">&lt;&lt;-</span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
          </span><span class="hljs-constant"><span class="pln">ALTER</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">TABLE</span></span><span class="pln"> distributors
            </span><span class="hljs-constant"><span class="pln">ADD</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">CONSTRAINT</span></span><span class="pln"> zipchk
              </span><span class="hljs-constant"><span class="pln">CHECK</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">char_length</span><span class="pun">(</span><span class="pln">zipcode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-constant"><span class="pln">NO</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">INHERIT</span></span><span class="pun">;</span><span class="pln">
        </span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
      </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
      dir</span><span class="pun">.</span><span class="pln">down </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
        execute </span><span class="pun">&lt;&lt;-</span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
          </span><span class="hljs-constant"><span class="pln">ALTER</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">TABLE</span></span><span class="pln"> distributors
            </span><span class="hljs-constant"><span class="pln">DROP</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">CONSTRAINT</span></span><span class="pln"> zipchk
        </span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
      </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

    add_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">users</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">home_page_url</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">string</span></span><span class="pln">
    rename_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">users</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email_address</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إن إستعمال دالة <code>reversible</code> سوف تتأكد من تنفيذ <code>excute</code> سطور الكود في الترتيب الصحيح. ففي المثال السابق، سيتم عكس التهجير بالترتيب، فسيتم تشغيل البلوك <code>down</code> بعد حذف عامود <code>home_page_url</code> و قبل إضافة جدول <code>distributors</code>. في بعض الأحيان، لن يُمكن عكس عملية التهجير. لأنه –وعلى سبيل المثال- قد تؤدي إلى تدمير بعض البيانات. في هذه الحالات يُمكنك إستخدام أمر <code>ActiveRecord::IrreversibleMigration</code> في البلوك <code>down</code>. و إذا حاول أحد عكس التهجير فإن رسالة خطأ <code>error message</code> ستُخبره بأن هذا الأمر غير مُمكن.
</p>

<h3 id="310-إستعمال-دوال-updown">
	3.10 إستعمال دوال up/down
</h3>

<p>
	يُمكنك إستعمال الأسلوب القديم للتهجير بدوال <code>up</code> و <code>down</code> بدلًا من إستعمال دالة <code>change</code>. فإن دالة <code>up</code> يجب أن تصف فيها التغيرات التي تريد عملها في الإسكيما. و دالة <code>down</code> ستقوم بعكس التغيير الذي قامت به دالة <code>up</code>. بإختصار، فإنك إذا قُمت بتطبيق دالة <code>up</code> ثُم بعد ذلك دالة <code>down</code> فيجب ألا يحدث تغيير على قاعدة البيانات. و من المُرجح أن تكون التغييرات التي ستقوم بها دالة <code>up</code> يُمكن عكسها بسهولة. المثال السابق ذكره في قسم (3.9 أمر العكس) سيؤدي وظيفته هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">ExampleMigration</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">up
    create_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">distributors</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">zipcode</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

    </span><span class="hljs-comment"><span class="com"># add a CHECK constraint</span></span><span class="pln">
    execute </span><span class="pun">&lt;&lt;-</span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
      </span><span class="hljs-constant"><span class="pln">ALTER</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">TABLE</span></span><span class="pln"> distributors
        </span><span class="hljs-constant"><span class="pln">ADD</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">CONSTRAINT</span></span><span class="pln"> zipchk
        </span><span class="hljs-constant"><span class="pln">CHECK</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">char_length</span><span class="pun">(</span><span class="pln">zipcode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">);</span><span class="pln">
    </span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">

    add_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">users</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">home_page_url</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">string</span></span><span class="pln">
    rename_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">users</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email_address</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">down
    rename_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">users</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email_address</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">email</span></span><span class="pln">
    remove_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">users</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">home_page_url</span></span><span class="pln">

    execute </span><span class="pun">&lt;&lt;-</span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
      </span><span class="hljs-constant"><span class="pln">ALTER</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">TABLE</span></span><span class="pln"> distributors
        </span><span class="hljs-constant"><span class="pln">DROP</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">CONSTRAINT</span></span><span class="pln"> zipchk
    </span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">

    drop_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">distributors</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	في بعض الأحيان، لن يُمكن عكس عملية التهجير. لأنه –وعلى سبيل المثال- قد تؤدي إلى تدمير بعض البيانات. في هذه الحالات يُمكنك إستخدام أمر <code>ActiveRecord::IrreversibleMigration</code> في البلوك <code>down</code>. و إذا حاول أحد عكس التهجير فإن رسالة خطأ <code>error message</code> ستُخبره بأن هذا الأمر غير مُمكن.
</p>

<h3 id="311-عكس-تهجيرات-سابقة">
	3.11 عكس تهجيرات سابقة
</h3>

<p>
	يُمكنك إستعمال دالة <code>revert</code> في Active Record لعكس التهجيرات السابقة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="pln">require_relative </span><span class="hljs-string"><span class="str">'20121212123456_example_migration'</span></span><span class="pln">

</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">FixupExampleMigration</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    revert </span><span class="hljs-constant"><span class="typ">ExampleMigration</span></span><span class="pln">

    create_table</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">apples</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">variety</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	دالة <code>reverse</code> أيضًا تقبل عكس مجموعة block من الأوامر. حيث إن هذا سيكون مُفيد في عكس أجزاء مُعينة فقط من تهجير قُمت به مُسبقًا. على سبيل المثال، إفترض أنك إحتحجت إستخدام تحقيقات السحل النشط على التهجير ExampleMigration في مكان إستخدام CHECK لتأكيد الرقم البريدي zipcode.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7349_10" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">DontUseConstraintForZipcodeValidationMigration</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    revert </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
      </span><span class="hljs-comment"><span class="com"># copy-pasted code from ExampleMigration</span></span><span class="pln">
      reversible </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">dir</span><span class="pun">|</span><span class="pln">
        dir</span><span class="pun">.</span><span class="pln">up </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
          </span><span class="hljs-comment"><span class="com"># add a CHECK constraint</span></span><span class="pln">
          execute </span><span class="pun">&lt;&lt;-</span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
            </span><span class="hljs-constant"><span class="pln">ALTER</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">TABLE</span></span><span class="pln"> distributors
              </span><span class="hljs-constant"><span class="pln">ADD</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">CONSTRAINT</span></span><span class="pln"> zipchk
                </span><span class="hljs-constant"><span class="pln">CHECK</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">char_length</span><span class="pun">(</span><span class="pln">zipcode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">);</span><span class="pln">
          </span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
        dir</span><span class="pun">.</span><span class="pln">down </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
          execute </span><span class="pun">&lt;&lt;-</span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
            </span><span class="hljs-constant"><span class="pln">ALTER</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">TABLE</span></span><span class="pln"> distributors
              </span><span class="hljs-constant"><span class="pln">DROP</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">CONSTRAINT</span></span><span class="pln"> zipchk
          </span><span class="hljs-constant"><span class="pln">SQL</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
      </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

      </span><span class="hljs-comment"><span class="com"># The rest of the migration was ok</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إن نفس التهجير يُمكن كتابته بدون إستخدام <code>revert</code> و لكن ستقوم بعمل المزيد من الخطوات: عكس ترتيب الأمر <code>create_table</code> و الأمر <code>reversible</code>، و إستبدال الأمر <code>create_table</code> بالأمر <code>drop_table</code>، و أخيرًا ستقوم بعكس أمرين <code>up</code> و <code>down</code> و العكس صحيح. هذا كُله يتم عمله بواسطة دالة <code>revert</code>.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			**إذا أردت تُضيف تأكيدات check constraints في المثال أعلاه، و ستقوم بإستعمال ملف <code>structre.sql</code> لتخطي هذا.
		</p>
	</div>
</blockquote>

<p>
	سنتابع في الدرس التالي ما تبقى من هذا الدليل التعليمي حول تهجير Active Record
</p>

<p>
	المصدر:<br>
	توثيقات <a href="http://guides.rubyonrails.org/active_record_migrations.html" rel="external nofollow">Ruby on Rails</a>.
</p>
]]></description><guid isPermaLink="false">566</guid><pubDate>Tue, 28 Nov 2017 11:21:00 +0000</pubDate></item><item><title>Active Record Migrations: &#x646;&#x638;&#x631;&#x629; &#x639;&#x627;&#x645;&#x629; &#x648;&#x637;&#x631;&#x64A;&#x642;&#x629; &#x625;&#x646;&#x634;&#x627;&#x626;&#x647;</title><link>https://academy.hsoub.com/programming/ruby/rails/active-record-migrations-%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D9%88%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A6%D9%87-r563/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_11/21.png.23922b3ec2a3802f18431bf29607e537.png" /></p>

<p>
	إن التهجير من أهم مزايا Active Record، حيث يسمح لك بتطوير قاعدة البيانات بسهولة مع مرور الزمن. فبدلًا من إعادة كتابة مُخططات قاعدة البيانات بسطور SQL من جديد، سيسمح لك التهجير باستعمال كود Ruby موحد المجال Domain – specific language لوصف التعديلات اللازمة التي ستقوم بها على جداولك.
</p>

<h2 id="1-نظرة-عامة-على-التهجير">
	1 نظرة عامة على التهجير
</h2>

<p>
	التهجير هو الطريقة الملائمة لتبديل أجزاء و مُخططات قاعدة البيانات بمرور الزمن بطريقة سهلة و متناسقة. ونقوم بإستعمال لُغة Ruby موحدة المجال DSL بدلًا من كتابة العديد من سطور SQL مما يسمح للتغيرات بأن تكون مُستقلة تمامًا عن قاعدة البيانات و لا تؤثر عليها سلبًا. يُمكنك التفكير في التهجير على أنه عمل تحديث جديد لقاعدة البيانات. ففي بداية الإسكيما تكون فارغة، ثُم بعد ذلك تقوم عمليات التهجير بإضافة الجداول، العواميد، أو المدخلات. و Active Record يقوم بعمل هذه التحديثات على الإسكيما من الحالة التي كانت عليها قبل التحديث (أو في النُسخة السابقة). كما سيقوم Active Record بتحديث ملف <code>db/schema.rb</code> ليُناسب بناء قاعدة البيانات بعد التحديث.<br>
	مثال على التهجير
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">CreateProducts</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span><span class="pln">
  </span><span class="kwd">def</span><span class="pln"> change
    create_table </span><span class="pun">:</span><span class="pln">products </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">string </span><span class="pun">:</span><span class="pln">name
      t</span><span class="pun">.</span><span class="pln">text </span><span class="pun">:</span><span class="pln">description

      t</span><span class="pun">.</span><span class="pln">timestamps
    </span><span class="kwd">end</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	في المثال السابق، قُمنا بعملية تهجير حيث أضفنا جدول جديد يُسمى <code>products</code> يحتوي على عامود نصي يُسمى <code>name</code> و عامود آخر يُسمى <code>description</code>. وسيتم إضافة عامود مفتاح أساسي يُسمى id ضمنيًا، لأنه –كما علمنا من قبل- المفتاح الرئيسي الإفتراضي لجميع نماذج Active Record. آما أمر <code>timestamps</code> يُضيف عامودين، صُنع في <code>created_at</code> وتم تحديثه في <code>updated_at</code>. و تلك العواميد الخاصة يتم إدارتها و تحديثها تلقائيًا بواسطة Active Record. لاحظ أن عملية التغير التي نقوم بها تتحرك أمامًا مع مرور الوقت، فقبل تشغيل التهجير <code>run migration</code> لن يوجد لدينا ذلك الجدول، و بمجرد تشغيل كود التهجير سنحصل على الجدول، و العكس صحيح! فإن Active Record يُمكنه عكس عملية التهجير بإستخدام أمر العودة <code>Roll back</code> و سيُحذف الجدول الجديد. بعض قواعد البيانات تدعم الصفقات Transactions* مع التغيرات التي تحدث للإسكيما. خاصية التهجير مُحاطة بتلك الصفقات Transactions. و لكن إذا كانت قاعدة البيانات لا تسمح بالصفقات، فإن التهجير سيقوم بإلغاء الأجزاء التي لم تطرأ عليها تلك التغيرات.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			*الصفقات Transaction هي سلسلة من العمليات تتم على وحدة مُفردة من قاعدة البيانات. و تكون مُستقلة تمامًا عن باقي العمليات.
		</p>
	</div>
</blockquote>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			مثال: بعض السجلات Queries لا تعمل داخل تلك الصفقات، فيمكنك تعطيل خاصية تلك الصفقات Transactions بإستخدام الأمر <code>disable_ddl_transaction!</code> ثُم يُمكنك إستخدام التهجير بعد ذلك.<br>
			أما إذا رغبت بعمل التهجير على شيئًا ما، لا يدعم Active Record العمليات العكسية بهذا الشيئ، فُيمكنك إستخدام أمر <code>reversible</code>.
		</p>
	</div>
</blockquote>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">ChangeProductsPrice</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    reversible </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">dir</span><span class="pun">|</span><span class="pln">
      change_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
        dir</span><span class="pun">.</span><span class="pln">up   </span><span class="pun">{</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">change </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">price</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">string</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
        dir</span><span class="pun">.</span><span class="pln">down </span><span class="pun">{</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">change </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">price</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">integer</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	و بدلًا من إستخدام أمر <code>change</code> ستستخدم أوامر <code>up</code> و <code>down</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">ChangeProductsPrice</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">up
    change_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">change </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">price</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">string</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">down
    change_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">change </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">price</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">integer</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<h2 id="2-إنشاء-التهجير">
	2 إنشاء التهجير
</h2>

<h3 id="21-إنشاء-تهجير-مستقل-و-منفرد-بنفسه">
	2.1 إنشاء تهجير مُستقل و مُنفرد بنفسه
</h3>

<p>
	إن عمليات التهجير تكون مُخزنة داخل ملف يوجد في <code>db/migrate</code>، و يوجد ملف لكل عملية تهجير حدثت على فئة مُعينة <code>class</code>. إسم الملف يتخذ الصيغة الآتية <code>YYYYMMDDHHMMSS_creat_products.rb</code> و هي تحتوي على صيغة الوقت التي حدث فيه التهجير، ثم علامة “_” ثم إسم عملية التهجير. إن هذا الإسم يجب أن يُطابق إسم الفئة <code>class</code> التي لحق بها, فعلى سبيل المثال، إن كان إسم التهجير <code>20080906120000_creat_products.rb</code> فيجب أن يُعرف فئة <code>class</code> إسمها CreatProducts. آما بالنسبة للوقت المُلحق بالإسم، فإن Rails تستعمله لترتيب التهجيرات و ترتيب كيفية عملها. لذلك إذا قُمت بنسخ تهجير ما من تطبيق آخر. فيجب أن تلتفت لهذا الأمر. و حساب الوقت بالضبط أي الدقيقة و الثانية لأمرٌ صعب. لذلك يوفر Active Record مولد لصُنع هذا الأمر.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">bin</span><span class="pun">/</span><span class="pln">rails generate migration </span><span class="hljs-constant"><span class="typ">AddPartNumberToProducts</span></span></code></pre>

<p>
	سيصنع الكود أعلاه تهجير فارغ، لكنه مُسمى بتسمية صحيحة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">AddPartNumberToProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إذا كان التهجير على هيئة <code>AddXXXToYYY</code> أو <code>RemoveXXXfromYYY</code> أي يحتوي على أوامر إضافة أو حذف و يحتوي أيضًا على عواميد تحتوي على الأسماء <code>names</code> و الأنواع <code>types</code>، فسيتم صُنع عواميد مُناسبة مثل <code>add_column</code> و <code>remove_column</code>. و الكود أدناه مثال على ذلك.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs vhdl"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-keyword"><span class="pln">generate</span></span><span class="pln"> migration </span><span class="typ">AddPartNumberToProducts</span><span class="pln"> part_number</span><span class="pun">:</span><span class="hljs-typename"><span class="kwd">string</span></span></code></pre>

<p>
	سينتج عنه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">AddPartNumberToProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    add_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">string</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	و يُمكنك أيضًا عمل فهرسة للعواميد الجديدة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs vhdl"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-keyword"><span class="pln">generate</span></span><span class="pln"> migration </span><span class="typ">AddPartNumberToProducts</span><span class="pln"> part_number</span><span class="pun">:</span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">:</span><span class="pln">index</span></code></pre>

<p>
	سينتج عنه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">AddPartNumberToProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    add_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">string</span></span><span class="pln">
    add_index </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	و بنفس الطريقة يُمكنك عمل تهجير ليزيل عامود بإستخدام هذا الكود.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs vhdl"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-keyword"><span class="pln">generate</span></span><span class="pln"> migration </span><span class="typ">RemovePartNumberFromProducts</span><span class="pln"> part_number</span><span class="pun">:</span><span class="hljs-typename"><span class="kwd">string</span></span></code></pre>

<p>
	سينتج عنه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">RemovePartNumberFromProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    remove_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">string</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	كما أنك لست مُقيد بنوع واحد من العواميد لإنتاجه، مثال على ذلك
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs cs"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails generate migration </span><span class="typ">AddDetailsToProducts</span><span class="pln"> part_number</span><span class="pun">:</span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pln"> price</span><span class="pun">:</span><span class="hljs-keyword"><span class="kwd">decimal</span></span></code></pre>

<p>
	سينتج عنه
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">AddDetailsToProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    add_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">string</span></span><span class="pln">
    add_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">price</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">decimal</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	<strong>لاحظ هُنا تحديد نوع البيانات الذي قُمنا به </strong>أما إذا كان التهجير يتخذ صيغة <code>CreateXXX</code> و مُتبع بقائمة بأسماء و أنواع العواميد، فإن التهجير سيقوم بعمل جدول <code>XXX</code> يحتوي على تلك العواميد، مثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs vhdl"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-keyword"><span class="pln">generate</span></span><span class="pln"> migration </span><span class="typ">CreateProducts</span><span class="pln"> name</span><span class="pun">:</span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pln"> part_number</span><span class="pun">:</span><span class="hljs-typename"><span class="kwd">string</span></span></code></pre>

<p>
	و هذا سينتج عنه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CreateProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    create_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">part_number</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	وكالعادة، فإنه يُمكنك تعديل ما يتم توليده من قبل التهجير عن طريق الإضافة و الحذف. عند طريق التعديل على هذا الملف <code>db/migrate/YYYMMDDHHMMSS_add_details_to_products.rb</code>، على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">bin</span><span class="pun">/</span><span class="pln">rails generate migration </span><span class="hljs-constant"><span class="typ">AddUserRefToProducts</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">user</span><span class="pun">:</span></span><span class="pln">references</span></code></pre>

<p>
	و هذا سينتج عنه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">AddUserRefToProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    add_reference </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">user</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">foreign_key</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	هذا التهجير سوف يصنع عامود <code>user_id</code> مع فهرس مُناسب. و هُناك أيضًا العديد من الخيارات الأخرى لدالة <code>add_reference</code> سنتطرق إليها فيما بعد. هذا الكود سيولد جداول مُدمجة <code>Join tables</code> إذا إستعملت <code>JoinTable</code> كجزء من إسم التهجير، مثال:<br><strong>الجداول المُدمجة <code>Join Tables</code> هي تجميع لعدد معين من العواميد من جدول واحد أو أكثر من جدول.</strong>
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">bin</span><span class="pun">/</span><span class="pln">rails g migration </span><span class="hljs-constant"><span class="typ">CreateJoinTableCustomerProduct</span></span><span class="pln"> customer product</span></code></pre>

<p>
	و هذا سوف ينتج التهجير الآتي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CreateJoinTableCustomerProduct</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    create_join_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">customers</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      </span><span class="hljs-comment"><span class="com"># t.index [:customer_id, :product_id]</span></span><span class="pln">
      </span><span class="hljs-comment"><span class="com"># t.index [:product_id, :customer_id]</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<h3 id="22-موالدات-النماذج">
	2.2 موالدات النماذج
</h3>

<p>
	إن مولدات النماذج و الإسكافولد Model and Scaffold Generators يُمكنها صُنع التهجير المُناسب لإضافة نموذج جديد. حيث سيحتوي التهجير على التعليمات اللازمة لصناعة الجداول المُناسبة. فإذا حددت العواميد التي تريدها، سيتم إضافة سطور الكود اللازمة لإضافة تلك العواميد، مثال:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			** الإسكافولد Scaffold هو جزء من النمط البرمجي MVC حيثُ يُمكنك إختيار جزء مُعين من قاعدة البيانات للعمل عليه.<br>
			** النموذج Model : -حتى لا ننسى- فإنه الجزء الرئيسي من النمط البرمجي MVC و هو الجزء المسئول عن البيانات، المنطق في التعامل و أوامر التطبيقات، و هو مُنفصل تمامًا عن قاعدة البيانات.
		</p>
	</div>
</blockquote>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs applescript"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails generate model </span><span class="typ">Product</span><span class="pln"> </span><span class="hljs-property"><span class="pln">name</span></span><span class="pun">:</span><span class="hljs-type"><span class="kwd">string</span></span><span class="pln"> description</span><span class="pun">:</span><span class="hljs-type"><span class="pln">text</span></span></code></pre>

<p>
	و ذلك سوف يصنع هذا التهجير:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CreateProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    create_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">text </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">description</span></span><span class="pln">

      t</span><span class="pun">.</span><span class="pln">timestamps
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	و بالطبع يُمكنك إضافة أي عدد تشاءه
</p>

<h3 id="23-تعدية-المعدلات">
	2.3 تعدية المُعدلات
</h3>

<p>
	يُمكنك كتابة كود لتعدي المُعدلات Modifiers لأنهم قد تُقيدك. فإذا قُمت بتشغيل هذا الكود:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">bin</span><span class="pun">/</span><span class="pln">rails generate migration </span><span class="hljs-constant"><span class="typ">AddDetailsToProducts</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'price:decimal{5,2}'</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">supplier</span><span class="pun">:</span></span><span class="pln">references</span><span class="pun">{</span><span class="pln">polymorphic</span><span class="pun">}</span></code></pre>

<p>
	سوف يُنتج هذا التهجير:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5377_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">AddDetailsToProducts</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    add_column </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">price</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="kwd">decimal</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">precision</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">scale</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pln">
    add_reference </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">products</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">supplier</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">polymorphic</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	سنتابع في الدروس القادمة بقية أجزاء دليل تعليم Active Record Migrations..<br>
	المصدر:<br><a href="http://guides.rubyonrails.org/" rel="external nofollow">توثيقات Ruby on Rails.</a>
</p>
]]></description><guid isPermaLink="false">563</guid><pubDate>Tue, 21 Nov 2017 11:42:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x633;&#x62A;&#x62E;&#x62F;&#x645; &#x645;&#x643;&#x62A;&#x628;&#x629; Webpacker &#x628;&#x62F;&#x644;&#x64B;&#x627; &#x645;&#x646; Asset Pipline &#x641;&#x64A; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Rails</title><link>https://academy.hsoub.com/programming/ruby/rails/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-webpacker-%D8%A8%D8%AF%D9%84%D9%8B%D8%A7-%D9%85%D9%86-asset-pipline-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-rails-r562/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_11/19-2.png.9d772c37392439433921fa3b45d203b0.png" /></p>

<p>
	أعترف بأنّي لا أمتلك خبرة كبيرة في مكتبة Webpacker الجديدة في إطار العمل Ruby on Rails، ولكنّي قرّرت الاعتماد على هذه المكتبة تمامًا والاستغناء كلّيًا عن مكتبة Sprockets للتعامل مع الأصول assets. وباعتباري أحد متّبعي مبدأ Convention Over Configuration فقد حاولت جاهدًا إيجاد الطريقة التي يمكن الاصطلاح عليها في تشييد تطبيق Webpacker. هذه المكتبة في أيامها الأولى لذا أظنّ أنّ فريق مطوري Rails لم يقوموا بهذا الأمر أيضًا، وأعتقد بأنّ مجتمع المطوّرين سيجد حلًّا لهذه المسألة قريبًا. على أي حال، إليك الطريقة التي اتبعتها في استبدال asset pipeline بـ Webpacker.
</p>

<p>
	إن كنت ترغب في العمل على مشروع جديد، فاستخدم الأمر:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<span class="pln">rails new blank </span><span class="pun">--</span><span class="pln">skip</span><span class="pun">-</span><span class="pln">sprockets </span><span class="pun">--</span><span class="pln">webpack</span></pre>

<p>
	ليتم إنشاء تطبيق Rails جديد مع الاستغناء عن مكتبة Sprockets وإضافة المكتبة Webpacker. أما لو كنت ترغب في إضافة Webpacker إلى مشروع قائم فعليك <a href="https://github.com/rails/webpacker" rel="external nofollow">بمراجعة التوثيقات</a>.
</p>

<p>
	بعد ذلك احذف بعض الجواهر gems والتي لم نعد بحاجة إليها من ملف <code>Gemfile</code>، وهي sass-rails، uglifier و coffee-rails. كذلك يمكنك التخلص من المجلد <code>app/assets</code> لأنّنا لم نعد بحاجة إليه بعد الآن.
</p>

<p>
	لنلق نظرة في البداية على محتويات ملف <code>application.js</code> الذي يتم إنشاؤه افتراضيًّا بواسطة Webpacker.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs vhdl"><span class="hljs-comment"><span class="com">/* eslint no-console:0 */</span></span><span class="pln">
</span><span class="com">// This </span><span class="hljs-keyword"><span class="com">file</span></span><span class="com"> </span><span class="hljs-keyword"><span class="com">is</span></span><span class="com"> automatically compiled by Webpack, along </span><span class="hljs-keyword"><span class="com">with</span></span><span class="com"> any other files</span><span class="pln">
</span><span class="com">// present </span><span class="hljs-keyword"><span class="com">in</span></span><span class="com"> this directory. You</span><span class="hljs-attribute"><span class="com">'re</span></span><span class="com"> encouraged </span><span class="hljs-keyword"><span class="com">to</span></span><span class="com"> place your actual application logic </span><span class="hljs-keyword"><span class="com">in</span></span><span class="pln">
</span><span class="com">// a relevant structure within app/javascript </span><span class="hljs-keyword"><span class="com">and</span></span><span class="com"> only </span><span class="hljs-keyword"><span class="com">use</span></span><span class="com"> these pack files </span><span class="hljs-keyword"><span class="com">to</span></span><span class="com"> reference</span><span class="pln">
</span><span class="com">// that code so it</span><span class="hljs-attribute"><span class="com">'ll</span></span><span class="com"> be compiled.</span><span class="pln">
</span><span class="com">//</span><span class="pln">
</span><span class="com">// </span><span class="hljs-keyword"><span class="com">To</span></span><span class="com"> reference this </span><span class="hljs-keyword"><span class="com">file</span></span><span class="com">, add &lt;%= javascript_pack_tag </span><span class="hljs-attribute"><span class="com">'application</span></span><span class="com">' %&gt; </span><span class="hljs-keyword"><span class="com">to</span></span><span class="com"> the appropriate</span><span class="pln">
</span><span class="com">// layout </span><span class="hljs-keyword"><span class="com">file</span></span><span class="com">, like app/views/layouts/application.html.erb</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="hljs-attribute"><span class="str">'Hello</span></span><span class="str"> World from Webpacker'</span><span class="pun">)</span></code></pre>

<p>
	تشير التعليقات الواردة في هذا الملف إلى أن المجلد <code>app/javascript/packs</code> هو نقطة الولوج entry point إلى الحزم المستخدمة في التطبيق، وأنّ عليك وضع التطبيق الحقيقي في المجلد <code>app/javascript</code>.
</p>

<h2 id="ترتيب-الملفات-والمجلدات">
	ترتيب الملفّات والمجلّدات
</h2>

<p>
	لقد نظّمت تطبيق Webpacker الخاصّ بي كما هو موضح أدناه، والتطبيق يحمل اسم blog. سترى أنّي قد أدرجت تطبيق JavaScript الحقيقي في المجلد <code>app/javascript/blog</code> بدلًا من <code>app/javascript</code> ولم أقم بذلك اعتباطًا.
</p>

<p>
	أولًا: يعني هذا أن بمقدوري إضافة العديد من التطبيقات إلى المشروع الواحد وحسب الحاجة، بدلًا من تكديس جميع الشيفرات جنبًا إلى جنب.
</p>

<p>
	ثانيًا: ستتيح لي هذه الطريقة امتلاك نقطة ولوج حقيقية للحزم وهذا ما سأوضّحه الآن.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs brainfuck"><span class="hljs-comment"><span class="pln">blog</span></span><span class="pln">
</span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">app</span></span><span class="pln">
</span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">javascript</span></span><span class="pln">
</span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">blog</span></span><span class="pln">
</span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">fonts</span></span><span class="pln">
</span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">images</span></span><span class="pln">
</span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">styles</span></span><span class="pln">
</span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">index</span></span><span class="hljs-string"><span class="pun">.</span></span><span class="hljs-comment"><span class="pln">js</span></span><span class="pln">
</span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">packs</span></span><span class="pln">
</span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-comment"><span class="pun">|</span></span><span class="pln">   </span><span class="hljs-literal"><span class="pun">+</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="hljs-literal"><span class="pun">-</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pln">application</span></span><span class="hljs-string"><span class="pun">.</span></span><span class="hljs-comment"><span class="pln">js</span></span></code></pre>

<p>
	لنلق نظرة الآن إلى ملف <code>app/javascript/packs/application.js</code> وهو نقطة الولوج إلى حزمتي، وهو ملفّ بسيط للغاية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs java"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'blog'</span></span><span class="pun">;</span></code></pre>

<p>
	سيتم استيراد التطبيق وتشغيل الملف <code>app/javascript/blog/index.js</code> والذي سيصبح نقطة الولوج إلى تطبيق JavaScript الخاصّ بي. بهذه الطريقة أحافظ على نقطة الولوج بسيطة قدر الإمكان أما ما تبقى من الشيفرة فيكون ضمن التطبيق.
</p>

<p>
	جدير بالذكر كذلك أنّك لست ملزمًا بتسمية المجلد - والملفّ - باسم blog، بل يمكنك استخدام أي اسم تشاء، ولكنّني توخيت تبسيط الأمور بجعل اسم المجلد مطابقًا لاسم تطبيق Rails.
</p>

<p>
	والآن سنستخدم <code>javascript_pack_tag</code> للإشارة إلى تطبيقنا.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs bash"><span class="pln">javascript_pack_tag </span><span class="hljs-string"><span class="str">'application'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'data-turbolinks-track'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'reload'</span></span></code></pre>

<h2 id="مرحلة-التطوير">
	مرحلة التطوير
</h2>

<p>
	عند العمل في بيئة التطوير Development استخدم الأمر <code>bin/webpack-dev-server</code> وستتمّ مراقبة التطبيق وإعادة بنائه عند الحاجة، وإرسال التعديلات إلى المتصفّح. وبعد أن يصبح التطبيق جاهزًا للتجميع Compile يمكن استدعاء الأمر <code>bin/webpack</code> أو <code>rails assets:precompile</code>، ولكن سيتولى الخادوم هذه المهمّة على الأرجح.
</p>

<h2 id="مكتبتا-turbolinks-وrails-ujs">
	مكتبتا Turbolinks وRails UJS
</h2>

<p>
	إن كنت ستستخدم Turbolinks و Rails UJS في تطبيقك فعليك إعداد هاتين المكتبتين وتشغيلهما. من السهل استدعاء المكتبتين بواسطة الأمر <code>//= require</code> في حال كنت تستخدم asset pipline ولكن عند استخدام هاتين المكتبتين كوحدات فالأمر مختلف قليلًا. في البداية علينا تثبيت المكتبتين:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs livecodeserver"><span class="pln">yarn </span><span class="hljs-built_in"><span class="pln">add</span></span><span class="pln"> rails</span><span class="pun">-</span><span class="pln">ujs turbolinks</span></code></pre>

<p>
	بعد ذلك علينا استيراد المكتبتين وتشغيلهما في ملف <code>app/javascript/blog/index.js</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Rails</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'rails-ujs'</span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Turbolinks</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'turbolinks'</span></span><span class="pun">;</span><span class="pln">

</span><span class="typ">Rails</span><span class="pun">.</span><span class="pln">start</span><span class="pun">();</span><span class="pln">
</span><span class="typ">Turbolinks</span><span class="pun">.</span><span class="pln">start</span><span class="pun">();</span></code></pre>

<p>
	كما تلاحظ فقد اتبعنا نفس الأسلوب في استدعاء كلتا المكتبتين وتشغيلهما.
</p>

<h2 id="متغيرات-البيئة-environment-variables">
	متغيرات البيئة Environment Variables
</h2>

<p>
	يمكن الوصول إلى متغيرات البيئة عبر الشيفرات الخاصة بنا بعد تجميعها. عادة ما أضيف اللاحقة <code>.erb</code> إلى اسم الملف ثم أنفّذ شيئًا مماثلًا لهذا: <code>&lt;%= ENV['X_ENV_VAR'] %&gt;</code> ولكن هناك طريقة أفضل، إذ يمكن تهجير المتغيرات إلى <code>process.env</code> وكما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs rust"><span class="hljs-keyword"><span class="kwd">export</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">const</span></span><span class="pln"> STRIPE_API_KEY </span><span class="pun">=</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">STRIPE_API_KEY</span><span class="pun">;</span></code></pre>

<h2 id="أوراق-الأنماط-stylesheets">
	أوراق الأنماط Stylesheets
</h2>

<p>
	يمكن وبكل بساطة استيراد ملفات CSS أو Sass التي ترغب باستخدامها في التطبيق. لقد حدّدت الملف <code>app/javascript/blog/styles/app.scss</code> كنقطة ولوج Sass وبهذا أبقي جميع الملفات في مجلد <code>styles</code>، وتصبح عملية استيرادها إلى التطبيق أمرًا سهلًا للغاية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs java"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'./styles/app.scss'</span></span><span class="pun">;</span></code></pre>

<p>
	يمكن استخدام المحرّف <code>~</code> مع <code>import</code> وستبدأ عملية البحث عن الملف من المجلد <code>node_modules</code>، فلو أردت مثلًا استيراد مكتبة Bootstrap إلى التطبيق يمكنك استخدام الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs css"><span class="hljs-at_rule"><span class="lit">@</span><span class="hljs-keyword"><span class="lit">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'~bootstrap/scss/bootstrap'</span></span></span><span class="pun">;</span></code></pre>

<h2 id="الصور">
	الصور
</h2>

<p>
	لا تختلف الصور عن أوراق الأنماط في شيء، إذ يجب استيرادها في البداية لتتمكن من استخدامها في التطبيق. عادة ما أضع الصور في مجلد <code>app/javascript/blog/images</code> ثم أنشئ ملفًّا باسم <code>index.js</code> في نفس المجلد وظيفته استيراد جميع الصور في المجلد. فعلى سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs java"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'./logo.svg'</span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'./menu-open.svg'</span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'./menu-close.svg'</span></span><span class="pun">;</span></code></pre>

<p>
	عليك الانتباه إلى أنّ هذه الطريقة لن تُضمّن الصور في أوراق الأنماط، وإنما تدفعها إلى Webpacker لتكون متاحة للاستخدام في التطبيق. ويمكنك حينئذٍ استخدام الدالة المساعدة <code>asset_pack_path</code> في العرض للإشارة إلى هذه الملفات. فلو أردت مثلًا استخدام إحدى هذه الصور:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_4533_7" style="">
<code class="hljs asciidoc"><span class="hljs-header"><span class="pun">=</span><span class="pln"> image_tag asset_pack_path</span><span class="pun">(</span><span class="str">'logo.svg'</span><span class="pun">)</span></span></code></pre>

<p>
	إضافة إلى ذلك يمكنك الإشارة إلى الصور في CSS أو Sass وسيتلقّفها Webpacker بصورة تلقائية. وبصورة عامة يكون مسار الجذر نقطة الولوج الخاصّة بأوراق الأنماط لذا لن تكون بحاجة إلى استخدام المسارات المطلقة.
</p>

<h2 id="ختاما">
	ختامًا
</h2>

<p>
	كما شاهدت فإن الأمر يتطلب الكثير من العمل، وهذا هو الأسلوب الذي أتبعه في استخدام Webpacker الآن. حاولت البحث عن مقالات تعنى بتفصيل طريقة استخدام Webpacker ولكنّي لم أجد شيئًا يذكر في الوقت الحاضر. أنا متحمّس جدًّا لمعرفة طريقة الاستخدام القياسية لهذه المكتبة هذا في حال تمّ تحديدها في المستقبل.
</p>

<p>
	ترجمة - وبتصرّف - للمقال <a href="https://www.neontsunami.com/posts/replacing-rails-asset-pipeline-with-webpacker" rel="external nofollow">Replacing Rails Asset Pipeline with Webpacker</a> لصاحبه Dwight Conrad Watson.
</p>
]]></description><guid isPermaLink="false">562</guid><pubDate>Sun, 19 Nov 2017 16:07:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; Active Record : &#x627;&#x644;&#x62A;&#x633;&#x645;&#x64A;&#x629;&#x60C;&#x642;&#x631;&#x627;&#x621;&#x629; &#x648;&#x643;&#x62A;&#x627;&#x628;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;&#x60C; &#x627;&#x644;&#x62A;&#x648;&#x62B;&#x64A;&#x642;&#x60C; &#x627;&#x644;&#x627;&#x633;&#x62A;&#x62F;&#x639;&#x627;&#x621; &#x648;&#x627;&#x644;&#x62A;&#x647;&#x62C;&#x64A;&#x631;</title><link>https://academy.hsoub.com/programming/ruby/rails/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-active-record-%D8%A7%D9%84%D8%AA%D8%B3%D9%85%D9%8A%D8%A9%D8%8C%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA%D8%8C-%D8%A7%D9%84%D8%AA%D9%88%D8%AB%D9%8A%D9%82%D8%8C-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%AF%D8%B9%D8%A7%D8%A1-%D9%88%D8%A7%D9%84%D8%AA%D9%87%D8%AC%D9%8A%D8%B1-r560/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_11/14.png.5e84e5946927032a0145354eca41fcb6.png" /></p>

<p>
	سنتابع في هذا الدرس دليل Active Record، حيث تعلمنا في <a href="https://academy.hsoub.com/programming/ruby/rails/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-active-record-%D9%85%D8%A7%D9%87%D9%8A%D8%AA%D9%87%D8%8C-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D9%88%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-r557/" rel="">الدرس السابق</a> ماهية Active Record، استيراد الأكواد من اللغات الأخرى والنماذج. وسنتابع في هذا الدرس بقية دليل Active Record.
</p>

<h2 id="4-تخطي-طرق-التسمية-الخاصة-بـ-rails">
	4 تخطي طُرق التسمية الخاصة بـ Rails
</h2>

<p>
	ماذا تفعل إن إحتجت أن تستعمل طريقة أخرى للتسمية غير المُتبعة بـ Rails؟ لا يوجد مُشكلة حيث يُمكنك تخطي قواعد التسمية بسهولة. إن سجل التطبيق ApplicationRecord يستلهم من Active Record <code>ActiveRecord::Base</code> و هذا الأمر يُعطينا العديد من الطرق التي يُمكن إستخدامها لتخطي قواعد التسمية. فيُمكنك –مثلًا- إستعمال هذا الأمر <code>ActiveRecord::Base.table_name=</code> لتحديد الإسم المُناسب للجدول الذي تُريد إنشائه.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Product</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
  </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">table_name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"my_products"</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	إذا فعلت ذلك فيجب عليك أن تعرف إسم الفئة class التي تحمل الثوابت (<code>my_products.yml</code>) يدويًا بإستعمال هذا الأمر <code>set_fixture_class</code> في تعريف الاختبار الخاص بك <code>test definition</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs r"><span class="kwd">class</span><span class="pln"> </span><span class="typ">ProductTest</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ActiveSupport</span><span class="pun">::</span><span class="typ">TestCase</span><span class="pln">
  set_fixture_class my_products</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Product</span><span class="pln">
  fixtures </span><span class="pun">:</span><span class="pln">my_products
  </span><span class="hljs-keyword"><span class="pun">...</span></span><span class="pln">
</span><span class="kwd">end</span></code></pre>

<p>
	ومن المُمكن أيضًا تخطي تسمية الأعمدة التي تُستعمل كمفاتيح أساسية باستعمال الأمر: <code>ActiveRecord::Base.primary_key=</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Product</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">self</span></span><span class="pun">.</span><span class="pln">primary_key </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"product_id"</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<h2 id="5-قراءة-و-كتابة-البيانات-crud">
	5 قراءة و كتابة البيانات CRUD
</h2>

<p>
	إن CRUD هي إختصار الأربع كلمات الآتية: Create, Read, Update و Delete. Active Record يقوم –تلقائيًا- بصنع الدوال التي تسمح لتطبيقٍ ما بقراءة و تعديل البيانات الموجودة داخل جداولها.
</p>

<h3 id="51-أمر-create">
	5.1 أمر Create
</h3>

<p>
	يُمكن عمل كائنات objects في Active Record باستخدام رمز الشباك <code>hash</code> أو كما يُمكن تعيين خصائصها يدويًا بعد تعريفها. فإن دالة <code>new</code> سوف تُخرج كائن جديد. بينما دالة <code>create</code> سوف تُخرج كائن جديد و تقوم بحفظه في قاعدة البيانات. على سبيل المثال، بافتراض وجود نموذج model يُسمى <code>User</code> و خصائصه <code>name</code> و <code>occupation</code>، فإن دالة <code>method</code> سوف تقوم بصُنع النموذج و حفظه بقاعدة البيانات.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs profile"><span class="pln">user </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-filename"><span class="typ">User</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">name</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"David"</span></span><span class="pun">,</span><span class="pln"> occupation</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Code Artist"</span></span><span class="pun">)</span></code></pre>

<p>
	بينما إستعمال دالة <code>new</code> سوف تقوم بصُنع الكائن <code>object</code> و لكن بدون حفظه
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs avrasm"><span class="pln">user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">new</span></span><span class="pln">
user</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">name</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"David"</span></span><span class="pln">
user</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">occupation</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Code Artist"</span></span></code></pre>

<p>
	و عند كتابة <code>user.save</code> سوف يُحفظ الكائن في قاعدة البيانات. وبافتراض وجود block مُسبق، فإن كلاً من الأمرين <code>creat</code> و <code>new</code> سوف يقومان بإخضاع ذلك الكائن للبلوك block في البداية.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs livecodeserver"><span class="pln">user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="hljs-built_in"><span class="kwd">new</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">u</span><span class="pun">|</span><span class="pln">
  u</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"David"</span></span><span class="pln">
  u</span><span class="pun">.</span><span class="pln">occupation </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Code Artist"</span></span><span class="pln">
</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">end</span></span></span></code></pre>

<h3 id="52-أمر-read">
	5.2 أمر Read
</h3>

<p>
	إن Active Record يوفر واجهة برمجة تطبيقات قوية من أجل الولوج للبيانات الموجودة داخل قاعدة البيانات. في الأكواد التالية، سيكون هُناك عدة أمثلة للولوج إلى قواعد البيانات بإستخدام Active Record.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs vhdl"><span class="com"># </span><span class="hljs-keyword"><span class="com">return</span></span><span class="com"> a collection </span><span class="hljs-keyword"><span class="com">with</span></span><span class="com"> </span><span class="hljs-keyword"><span class="com">all</span></span><span class="com"> users</span><span class="pln">
users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">all</span></span></code></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># return the first user</span></span><span class="pln">
user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">first</span></code></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># return the first user named David</span></span><span class="pln">
david </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">find_by</span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'David'</span></span><span class="pun">)</span></code></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs oxygene"><span class="com"># find all users named David who are Code Artists </span><span class="hljs-keyword"><span class="com">and</span></span><span class="com"> sort </span><span class="hljs-keyword"><span class="com">by</span></span><span class="com"> created_at </span><span class="hljs-keyword"><span class="com">in</span></span><span class="com"> </span><span class="hljs-keyword"><span class="com">reverse</span></span><span class="com"> chronological </span><span class="hljs-keyword"><span class="com">order</span></span><span class="pln">
users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">where</span></span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'David'</span></span><span class="pun">,</span><span class="pln"> occupation</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Code Artist'</span></span><span class="pun">).</span><span class="hljs-keyword"><span class="pln">order</span></span><span class="pun">(</span><span class="pln">created_at</span><span class="pun">:</span><span class="pln"> </span><span class="pun">:</span><span class="hljs-keyword"><span class="pln">desc</span></span><span class="pun">)</span></code></pre>

<h3 id="53-أمر-update">
	5.3 أمر Update
</h3>

<p>
	يُمكنك إعادة التعديل على خصائص الكائن object و حفظ التغييرات في قاعدة البيانات.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs bash"><span class="pln">user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">find_by</span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'David'</span></span><span class="pun">)</span><span class="pln">
user</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Dave'</span></span><span class="pln">
user</span><span class="pun">.</span><span class="pln">save</span></code></pre>

<p>
	و يوجد طريق مُختصر لعمل التحديثات أيضًا بإستخدام <code>hash mapping</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs profile"><span class="pln">user </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-filename"><span class="typ">User</span><span class="pun">.</span><span class="pln">find_by</span><span class="pun">(</span><span class="pln">name</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'David'</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-filename"><span class="pln">user</span><span class="pun">.</span><span class="pln">update</span><span class="pun">(</span><span class="pln">name</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Dave'</span></span><span class="pun">)</span></code></pre>

<p>
	و هذه الطريقة مُفيدة إذا أردت أن تُحدث العديد من الخصائص في وقتٍ واحد. و لكن إذا أردت تحديث العديد من السجلات مرة واحدة، فيُمكنك إستخدام أمر <code>update_all</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs avrasm"><span class="typ">User</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">update</span></span><span class="pln">_all </span><span class="hljs-string"><span class="str">"max_login_attempts = 3, must_change_password = 'true'"</span></span></code></pre>

<h3 id="54-أمر-delete">
	5.4 أمر Delete
</h3>

<p>
	يُمكنك حذف أي كائن بعد تخزينه بقاعدة البيانات، باستخدام تلك الأكواد:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs profile"><span class="pln">user </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-filename"><span class="typ">User</span><span class="pun">.</span><span class="pln">find_by</span><span class="pun">(</span><span class="pln">name</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'David'</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-filename"><span class="pln">user</span><span class="pun">.</span><span class="pln">destroy</span></span></code></pre>

<h2 id="6-التوثيق-validation">
	6 التوثيق Validation
</h2>

<p>
	إن Active Record يسمح لك بعمل توثيق لحالة نماذج البيانات (models) قبل إدخالها في قواعد البيانات. هناك العديد من الطرق لتوثيق النماذج قبل إدخالها قواعد البيانات مثل التأكد من أن قيمة المُدخل ليست فارغة و أنها غير موجودة بالفعل في قاعدة البيانات أو أنها تتبع تنسيقًا معينًا و الكثير من الأمور التي يمكن استخدامها للتوثيق. إن التوثيق أمر في غاية الأهمية عند تثبيت البيانات داخل قاعدة البيانات. لذلك فإن الدوال <code>save</code> و<code>update</code> قد يُخرجوا لنا <code>false</code> عندما يفشل التوثيق و لن يقوما بأية عمليات في قاعدة البيانات. و تلك الدوال يوجد دوال مُناقضة لها (<code>!save</code> و <code>!update</code>) فيُخرجا إستثناء <code>ActiveRecord::RecordInvalid</code> في حالة فشل التوثيق، مثال على ذلك:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">User</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">name</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

user </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">User</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pln">
user</span><span class="pun">.</span><span class="pln">save  </span><span class="hljs-comment"><span class="com"># =&gt; false</span></span><span class="pln">
user</span><span class="pun">.</span><span class="pln">save</span><span class="pun">!</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># =&gt; ActiveRecord::RecordInvalid: Validation failed: Name can't be blank</span></span></code></pre>

<h2 id="7-دوال-الإستدعاء-callbacks">
	7 دوال الإستدعاء Callbacks
</h2>

<p>
	إن دوال الإستدعاء داخل Active Record تسمح لك بإرفاق الكود لحدث مُعين يتكرر في دورة تكرار النموذج model الخاص بك. وهذا الأمر يسمح لك بإضافة أفعال إلى نماذجك مشروطة بحدوث أحداث مُعينة. فعلى سبيل المثال: عند صُنع سجل جديد يقوم Active Record بتحديث آخر أو حذفه، إلخ.
</p>

<h2 id="8-التهجير-migrations">
	8 التهجير Migrations
</h2>

<p>
	إن Rails توفر لغة مُحددة المجال <code>domain-specific</code> لإدارة قواعد البيانات تُسمى بالتهجير. إن أوامر التهجير مُخزنة بملفات يتم إخراجها لأي قاعدة بيانات يتم دعمها من Active Record باستخدام الأمر <code>rake</code>، ها هو كود تهجير يقوم بإنشاء جدول:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1151_8" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CreatePublications</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    create_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">publications</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">title</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">text </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">description</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">references </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">publication_type</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">integer </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">publisher_id</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">publisher_type</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">boolean</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">single_issue</span></span><span class="pln">

      t</span><span class="pun">.</span><span class="pln">timestamps
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
    add_index </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">publications</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">publication_type_id</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	إن Rails تتقفى آثر الملفات التي سُلمت لقاعدة البيانات و توفر إمكانية إستعادة تلك القاعدة <code>rollback</code>. لذلك فلإنشاء جدول يجب عليك كتابة الأمر في <code>rails db:migrate</code> و إستعادته بإستخدام <code>db::rollback</code>.<br>
	لاحظ أن الكود المُستخدم أعلاه يُمكن إستخدامه بأي قاعدة بيانات مثل MySQL و PostgreSQL و Oracle و غيرها.
</p>

<p>
	من توثيقيات <a href="http://rubyonrails.org/" rel="external nofollow">Ruby on Rails</a>
</p>
]]></description><guid isPermaLink="false">560</guid><pubDate>Tue, 14 Nov 2017 17:54:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; Active Record : &#x645;&#x627;&#x647;&#x64A;&#x62A;&#x647;&#x60C; &#x627;&#x644;&#x627;&#x633;&#x62A;&#x64A;&#x631;&#x627;&#x62F; &#x648;&#x627;&#x644;&#x646;&#x645;&#x627;&#x630;&#x62C;</title><link>https://academy.hsoub.com/programming/ruby/rails/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-active-record-%D9%85%D8%A7%D9%87%D9%8A%D8%AA%D9%87%D8%8C-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D9%88%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-r557/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_11/5a07f1239514d_07-2(2).png.23009105e7bdfe2dc9d2c221f0019692.png" /></p>

<p>
	سنتابع في هذا الدرس من سلسلة تعليم إطار العمل <a href="https://academy.hsoub.com/tags/ruby%20on%20rails%20101/" rel="">Ruby on Rails</a> حيث سنتعرف على Active Record.
</p>

<h2>
	1 ما هو Active Record؟
</h2>

<p>
	Active Record هو جزء من النمط البرمجي MVC -شرحها بأسفل المقال- و هو المسئول عن جزء البيانات. حيث إن Active Record هو الجزء المسؤول عن عرض البيانات و خوارزميتها. فيسهل Active Record صنع و إستخدام عناصر البيانات التي تتطلب مساحة دائمة في قاعدة البيانات database. إن تطبيق نمط Active Record يُعتبر نفسه وصف و جزء من الـ ORM – يوجد تعريف بالأسفل- .<br><strong>** MVC- Model View Controller</strong> - هو نمط تم اعتماده كطريقة للبرمجة حيث يعتمد هذا النمط في الاساس على عزل ما هو مرأي للمستعمل (user interface) عن ما يتعلق بالبيانات(data) و طرق استخدامها، حيث ينفصل الجزء المختص بالبيانات عن الواجهة و يمكن عمل أكتر من مطور على المشروع بسلاسة و دون تعارض. من مثال المنصات التي تعمل بتلك الطريقة هي Laravel<br><strong>** ORM Object- Relational- Object</strong> هو تكنيك برمجي مستخدم لتحويل البيانات بين الأنظمة غير المتوافقة عن طريق تحويل الصفوف و الأعمدة إلى كائنات بإستخدام البرمجة الشيئية.
</p>

<h3 id="11-نمط-السجل-النشط">
	1.1 نمط Active Record
</h3>

<p>
	لقد عرف مارتن فويلر Active Record في كتابه Patterns of Enterprise Application Architecture وفي هذا التعريف أوضح ماهيته. في Active Record، يحمل الكائن object كلاً من البيانات الدائمة و العمليات التي ستتم عليها. Active Recordيعمل على ربط منطق الولوج إلى البيانات بالكائن بحيث يُعلم المُستخدمين كيفية إدخال و إخراج البيانات من قاعدة البيانات.
</p>

<h3 id="12-رسم-العلاقات-بين-الكائنات-object-relational-mapping">
	1.2 رسم العلاقات بين الكائنات Object Relational Mapping
</h3>

<p>
	يُرمز إلى هذا المصطلح بالإختصار ORM ، وهو تقنية تربط بين الكائنات المُختصة بتطبيقٍ ما مع جداول في نظام إدارة قواعد البيانات المتصلة. بإستعمال ORM يمكن تخزين و إستخدام خصائص و علاقات الكائنات في التطبيق بدون الحاجة إلى كتابة أوامر SQL بل بطريقة مُباشرة و بإستخدام أكواد أقل.
</p>

<h3 id="13السجل-النشط-كمنصة-orm">
	1.3 Active Record كمنصة ORM
</h3>

<p>
	Active Record يوفر لنا العديد من الإمكانيات، أهمها:
</p>

<ul>
<li>
		تمثيل النماذج models و بياناتها
	</li>
	<li>
		تمثيل الروابط بين تلك النماذج
	</li>
	<li>
		تمثيل البيانات الموروثة بين نماذج البيانات المُتصلة
	</li>
	<li>
		توثيق النماذج قبل تثبيتها بقواعد البيانات
	</li>
	<li>
		تطبيق عمليات قواعد البيانات بإستخدام إسلوب البرمجة الشيئية
	</li>
</ul>
<h2 id="2-سهولة-إستيراد-الأكواد-من-اللغات-الأخرى">
	2 سهولة إستيراد الأكواد من اللغات الأخرى
</h2>

<p>
	عند كتابة أحد التطبيقات بلغةٍ ما أو منصةٍ أخرى لإستعمالها في منصة ORM فإن هذه الأكواد تحتاج إلى الكثير من التهيئة configuration . و لكن هذا الأمر قد تم حله في Rails حيث ستحتاج إلى كتابة أكواد قليلة جداً لعمل التهيئة (وفي بعض الأحيان لن تحتاج إلى التهئية على الإطلاق) عند صنع نماذج Active Record. طريقة عمل هذه التهيئة تعتمد على الإستناد إلى تهيئة التطبيقات بالطريقة نفسها في معظم الأوقات بطريقة رئيسية. ومع ذلك، في بعض الأحيان ستحتاج إلى كتابة أكواد التهيئة عندما لا تتناسب التطبيقات التي تستوردها مع الطريقة الرئيسية للتهيئة في Rails.
</p>

<h3 id="21-طريقة-التسمية-naming">
	2.1 طريقة التسمية Naming
</h3>

<p>
	إن Active Record يستعمل قواعد تسمية تُساعد على صُنع الروابط بين النماذج و جداول قواعد البيانات. Rails ستقوم بتحويل أسماء الأصناف classes إلى صيغة الجمع لتناسب جدول قاعدة البيانات المناسب لها. على سبيل المثال، إذا كان لديك فئة تُسمى book فستحصل على جدول قاعدة بيانات يُسمى books. و إن Rails تستعمل آلية قوية لذلك تُمكنها من جمع الأسماء المنتظمة و الشاذة. و عند إستعمال فئة إسمها مكون من كلمتين، فإن قواعد التسمية تميل إلى طريقة CamelCase حيث سيحتوي جدول قاعدة البيانات على الكلمتين ذاتهم مفصولتين بإستخدام “_”. على سبيل المثال، فئة تُسمي BookClub فإن جدول قاعدة البيانات الخاص بها سيسمى book_clubs، و يجب أن نلاحظ أن الإسم المفرد تبدأ كلماته بحروف استهلالية Capital.
</p>

<center>
	<table border="1"><tbody>
<tr>
<td style="background-color: rgb(146, 14, 27); padding: 5px 10px; text-align: center; color: white;">
					Model / Class
				</td>
				<td style="background-color: rgb(146, 14, 27); padding: 5px 10px; text-align: center; color: white;">
					Table / Schema
				</td>
			</tr>
<tr>
<td style="padding: 5px 10px; text-align: center;">
					Article
				</td>
				<td style="padding: 5px 10px; text-align: center;">
					articles
				</td>
			</tr>
<tr>
<td style="padding: 5px 10px; text-align: center;">
					LineItem
				</td>
				<td style="padding: 5px 10px; text-align: center;">
					line_items
				</td>
			</tr>
<tr>
<td style="padding: 5px 10px; text-align: center;">
					Deer
				</td>
				<td style="padding: 5px 10px; text-align: center;">
					deers
				</td>
			</tr>
<tr>
<td style="padding: 5px 10px; text-align: center;">
					Mouse
				</td>
				<td style="padding: 5px 10px; text-align: center;">
					Mice
				</td>
			</tr>
<tr>
<td style="padding: 5px 10px; text-align: center;">
					Person
				</td>
				<td style="padding: 5px 10px; text-align: center;">
					people
				</td>
			</tr>
</tbody></table>
</center>

<h3 id="22-طريقة-تنظيم-قاعدة-البيانات-و-تخطيطها">
	2.2 طريقة تنظيم قاعدة البيانات و تخطيطها
</h3>

<p>
	إن Active Record يستعمل طريقة التسمية التي تحدثنا عنها لتسمية العواميد columns في جداول قواعد البيانات، إعتمادًا على غرض هذه العواميد.
</p>

<ul>
<li>
		<strong>المفاتيح الأجنبية Foreign Keys</strong> هي مفاتيح أساسية في جداول أخرى و يتم إستخدامها للربط بين قواعد البيانات ببعضها البعض. طريقة تسميتها تتبع النمط الآتي singularized_table_name_id مثال على ذلك item_id, order_id
	</li>
	<li>
		<strong>المفاتيح الأساسية Primary Keys</strong>: إن Active Record يقوم بعمل عامود مكون من أرقام integers يُسمى id و مهمته هو تمييز الجدول و عناصره، فعند إستخدام خاصية التهجير Active Record Migration لعمل جداول جديدة، سيتم عمل عامود المفاتيح الأساسية تلقائيًا.
	</li>
</ul>
<p>
	هُناك أيضًا بعض العواميد الإختيارية التي تُضيف مميزات جديدة لـ Active Record:
</p>

<ul>
<li>
		مفتاح <strong>created_at</strong> يقوم بتخزين وقت صُنع السجل مع مراعاة الوقت الحالي.
	</li>
	<li>
		مفتاح <strong>updated_at</strong> يقوم بتخزين وقت تحديث السجل مع مراعاة الوقت الحالى.
	</li>
	<li>
		مفتاح <strong>lock_version</strong> يضيف خاصية الإغلاق المتفائل لقاعدة البيانات
	</li>
	<li>
		مفتاح <strong>type</strong> يُحدد إذا ما كانت خاصية Single Table Inheritance أم لا
	</li>
	<li>
		مفتاح <strong>(association_name)_type</strong> يستخدم لتخزين النوع الخاص بـ polymorphic associations.
	</li>
	<li>
		مفتاح<strong> (table_name)_count</strong> يُستخدم لتخزين عدد الكائنات أو الأشياء objects الموجودة داخل علاقة ما، و على سبيل المثال: إذا كان لديك class تُسمى Article تحتوي على عامود يُسمى comments_count. سيقوم هذا المُفتاح بتخزين أعداد الـ comments الموجودة بكل Article.
	</li>
</ul>
<h2 id="3-صنع-نماذج-السجل-النشط">
	3 صُنع نماذج Active Record
</h2>

<p>
	إن صُنع نماذج Active Record لهو أمرٌ في غاية السهولة. كُل ما عليك فعله هو عمل صنف class فرعية من سجل التطبيق ApplicationRecord.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5122_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Product</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">ApplicationRecord</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	هذا سوف يصنع نموذج model يُسمى Product مُتصل بجدول يُسمى products بقاعدة البيانات فبواسطة ذلك سيُمكنك ربط الأعمدة الموجودة بكل صف في ذلك الجدول مع الخصائص الخاصة بنموذجك. فإعتبر أنك قُمت بإنشاء الجدول بإستخدام سطور SQL الآتية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5122_9" style="">
<span class="pln">CREATE TABLE products </span><span class="pun">(</span><span class="pln">
   id int</span><span class="pun">(</span><span class="lit">11</span><span class="pun">)</span><span class="pln"> NOT NULL auto_increment</span><span class="pun">,</span><span class="pln">
   name varchar</span><span class="pun">(</span><span class="lit">255</span><span class="pun">),</span><span class="pln">
   PRIMARY KEY  </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	بإستعمال طريقة تخطيط البيانات السابق ذكرها، يمكنك كتابة كود مثل الآتي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5122_11" style="">
<span class="pln">p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Product</span><span class="pun">.</span><span class="pln">new
p</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Some Book"</span><span class="pln">
puts p</span><span class="pun">.</span><span class="pln">name </span><span class="com"># "Some Book"</span></pre>

<p>
	وسنتابع في الدرس التالي التسمية،قراءة وكتابة البيانات، التوثيق، الاستدعاء والتهجير…
</p>

<p>
	من توثيقيات <a href="http://rubyonrails.org/" rel="external nofollow">Ruby on Rails</a>
</p>
]]></description><guid isPermaLink="false">557</guid><pubDate>Wed, 08 Nov 2017 07:04:00 +0000</pubDate></item><item><title>&#x625;&#x639;&#x627;&#x62F;&#x629; &#x647;&#x64A;&#x643;&#x644;&#x629; &#x627;&#x644;&#x634;&#x64A;&#x641;&#x631;&#x629; &#x648;&#x625;&#x636;&#x627;&#x641;&#x629; &#x646;&#x638;&#x627;&#x645; &#x627;&#x633;&#x62A;&#x64A;&#x62B;&#x627;&#x642; &#x628;&#x633;&#x64A;&#x637;</title><link>https://academy.hsoub.com/programming/ruby/rails/%D8%A5%D8%B9%D8%A7%D8%AF%D8%A9-%D9%87%D9%8A%D9%83%D9%84%D8%A9-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D9%88%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D8%A8%D8%B3%D9%8A%D8%B7-r533/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_09/59b510390566d_main(32).png.1069a15f1d27037f404e7e37947e31f5.png" /></p>

<p id="إعادة-هيكلة-الشيفرة-وإضافة-نظام-استيثاق-بسيط">
	هذا هو الجزء الأخير من سلسلة “<a href="https://academy.hsoub.com/tags/ruby%20on%20rails%20101/" rel="">مدخل إلى إطار العمل Ruby on Rails</a>” وفي هذا الجزء سنعيد هيكلة الشيفرة التي كتبناها في الأجزاء السابقة من السلسلة، وسنتعرّف إلى نظام الاستيثاق البسيط الذي يقدّمه <a href="https://academy.hsoub.com/programming/ruby/rails/" rel="">إطار العمل Rails</a>.
</p>

<h2 id="إعادة-هيكلة-الشيفرة">
	إعادة هيكلة الشيفرة
</h2>

<p>
	بعد أن أصبحت المقالات والتعليقات تعمل بصورة جيدة، لنلقِ نظرة على القالب <code>app/views/articles/show.html.erb</code> . يبدو الملف طويلًا جدًّا، لذا سنستخدم الملفات الجزئية لتنظيف وترتيب الشيفرة البرمجية.
</p>

<h3 id="تصيير-مجموعة-الملفات-الجزئية">
	تصيير مجموعة الملفات الجزئية
</h3>

<p>
	في البداية سننشئ ملفًّا جزئيًا خاصًّا بالتعليقات وظيفته عرض جميع التعليقات الخاصّة بالمقالة. أنشئ الملف <code>app/views/comments/_comment.html.erb</code> وأضف إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5331_7" style="">
<span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Commenter</span><span class="pun">:&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;%=</span><span class="pln"> comment</span><span class="pun">.</span><span class="pln">commenter </span><span class="pun">%&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Comment</span><span class="pun">:&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;%=</span><span class="pln"> comment</span><span class="pun">.</span><span class="pln">body </span><span class="pun">%&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">والآن</span><span class="pln"> </span><span class="pun">يمكنك</span><span class="pln"> </span><span class="pun">تعديل</span><span class="pln"> </span><span class="pun">الملف</span><span class="pln"> </span><span class="str">`app/views/articles/show.html.erb`</span><span class="pln"> </span><span class="pun">كما</span><span class="pln"> </span><span class="pun">يلي:</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Title</span><span class="pun">:&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;%=</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">title </span><span class="pun">%&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Text</span><span class="pun">:&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;%=</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">text </span><span class="pun">%&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Comments</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;%=</span><span class="pln"> render </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">comments </span><span class="pun">%&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Add</span><span class="pln"> a comment</span><span class="pun">:&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;%=</span><span class="pln"> form_for</span><span class="pun">([</span><span class="lit">@article</span><span class="pun">,</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">comments</span><span class="pun">.</span><span class="pln">build</span><span class="pun">])</span><span class="pln"> </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">|</span><span class="pln">f</span><span class="pun">|</span><span class="pln"> </span><span class="pun">%&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">commenter </span><span class="pun">%&gt;&lt;</span><span class="pln">br</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_field </span><span class="pun">:</span><span class="pln">commenter </span><span class="pun">%&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">body </span><span class="pun">%&gt;&lt;</span><span class="pln">br</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_area </span><span class="pun">:</span><span class="pln">body </span><span class="pun">%&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">submit </span><span class="pun">%&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;%</span><span class="pln"> </span><span class="kwd">end</span><span class="pln"> </span><span class="pun">%&gt;</span><span class="pln">

</span><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="str">'Edit'</span><span class="pun">,</span><span class="pln"> edit_article_path</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%&gt;</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="str">'Back'</span><span class="pun">,</span><span class="pln"> articles_path </span><span class="pun">%&gt;</span></pre>

<p>
	بهذه الطريقة سيتم تصيير الملف الجزئي في <code>app/views/comments/_comment.html.erb</code> لكلّ تعليق موجود في مجموعة <code>@article.comments</code>، وعندما يتنقّل التابع <code>render</code> بين عناصر مجموعة التعليقات فإنه يُسند كل تعليق إلى متغيّر محلي local variable يحمل اسم الملف الجزئي ذاته، وفي حالتنا هذه <code>comment</code> والذي يكون متوفّرًا في الملف الجزئي.
</p>

<h2 id="تصيير-الملف-الجزئي-الخاص-بالاستمارة">
	تصيير الملف الجزئي الخاصّ بالاستمارة
</h2>

<p>
	لنقم بإزالة قسم التعليقات الجديد إلى ملف جزئي خاصّ به، ومرة أخرى أنشئ ملفًّا باسم <code>_form.html.erb</code> في المجلد <code>app/views/comments/</code> وأضف إليه ما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5331_7" style="">
<code class="hljs xml"><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> form_for</span><span class="pun">([</span><span class="lit">@article</span><span class="pun">,</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">comments</span><span class="pun">.</span><span class="pln">build</span><span class="pun">])</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">f</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">commenter %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_field </span><span class="pun">:</span><span class="pln">commenter %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">body %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_area </span><span class="pun">:</span><span class="pln">body %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">submit %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span></code></pre>

<p>
	ثم عدّل الملف <code>app/views/articles/show.html.erb</code> ليصبح بالصورة التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5331_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Title:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">title %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Text:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">text %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">Comments</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> render </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">comments %&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">Add a comment:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> render </span><span class="hljs-comment"><span class="str">'comments/form'</span><span class="pln"> %&gt;</span></span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Edit'</span><span class="pun">,</span><span class="pln"> edit_article_path</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">)</span><span class="pln"> %&gt;</span></span></span><span class="pln"> |
</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Back'</span><span class="pun">,</span><span class="pln"> articles_path %&gt;</span></span></span></code></pre>

<p>
	يعرّف تابع <code>render</code> الثاني القالب الجزئي الذي نرغب في تصييره وهو <code>comments/form</code>، ونظرًا لوجود المحرّف / ضمن هذه السلسلة النصّية سيعرف Rails بأنّك ترغب في تصيير الملف <code>_form.html.erb</code> الموجود في المجلد <code>app/views/comments</code>.
</p>

<p>
	أما الكائن <code>@article</code> فسيكون متوفّرًا لأيّ ملفّ جزئي يتم تصييره في العرض لأنّنا عرّفناه كمتغيّر من نوع <code>instance</code>.
</p>

<h3 id="حذف-التعليقات">
	حذف التعليقات
</h3>

<p>
	إن القدرة على حذف التعليقات المزعجة هي من الميزات المطلوب توفرها في المدوّنة، ولتنفيذ ذلك سنحتاج إلى إضافة رابط لحذف التعليقات ضمن العرض وإلى حدث <code>destroy</code> في المتحكّم <code>CommentsController</code>.
</p>

<p>
	لذا سنضيف أوّلًا رابط الحذف ضمن الملفّ الجزئي <code>app/views/comments/_comment.html.erb</code> وكما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5331_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Commenter:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> comment</span><span class="pun">.</span><span class="pln">commenter %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Comment:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> comment</span><span class="pun">.</span><span class="pln">body %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Destroy Comment'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">comment</span><span class="pun">.</span><span class="pln">article</span><span class="pun">,</span><span class="pln"> comment</span><span class="pun">],</span></span><span class="pln">
               method</span><span class="pun">:</span><span class="pln"> </span><span class="pun">:</span><span class="kwd">delete</span><span class="pun">,</span><span class="pln">
               data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> confirm</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-comment"><span class="str">'Are you sure?'</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> %&gt;</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span>
</code></pre>

<p>
	سيؤدّي النقر على هذا الرابط إلى إرسال الفعل DELETE متمثّلًا بالرابط <code>/articles/:article_id/comments/:id</code> إلى المتحكّم <code>CommentsController</code>، والذي سيبحث بدوره - مستعينًا بهذا الرابط - عن التعليق المراد حذفه من قاعدة البيانات. لنضِف حدث <code>destroy</code> إلى المتحكّم في الملف <code>app/controllers/comments_controller.rb</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5331_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CommentsController</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationController</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">create
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article_id</span></span><span class="pun">])</span><span class="pln">
    </span><span class="hljs-variable"><span class="lit">@comment</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">comments</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">comment_params</span><span class="pun">)</span><span class="pln">
    redirect_to article_path</span><span class="pun">(</span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">)</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">destroy
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article_id</span></span><span class="pun">])</span><span class="pln">
    </span><span class="hljs-variable"><span class="lit">@comment</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">comments</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">id</span></span><span class="pun">])</span><span class="pln">
    </span><span class="hljs-variable"><span class="lit">@comment</span></span><span class="pun">.</span><span class="pln">destroy
    redirect_to article_path</span><span class="pun">(</span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">)</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="kwd">private</span><span class="pln">
    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">comment_params
      </span><span class="kwd">params</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">require</span></span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">comment</span></span><span class="pun">).</span><span class="pln">permit</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">commenter</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">body</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span>
</code></pre>

<p>
	سيبحث الحدث <code>destroy</code> عن التعليق المراد حذفه، ثم يعيّن موقعه في مجموعة <code>@article.comments</code> ثم يحذفه من قاعدة البيانات ويعيد توجيهنا إلى حدث <code>show</code> الخاصّ بالمقالة.
</p>

<h3 id="حذف-الكائنات-المترابطة">
	حذف الكائنات المترابطة
</h3>

<p>
	من البديهي أنّه عند حذف مقالة معيّنة فإن من الواجب أن يتم حذف التعليقات المرتبطة بها، وإلا فستشغل هذه التعليقات مساحة ضمن قاعدة البيانات دون أيّ فائدة. يتيح لنا Rails استخدام الخيار <code>dependent</code> لتحقيق ذلك. توجّه إلى نموذج <code>Article</code> (<code>app/models/article.rb</code>) وعدّله بالصورة التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5331_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Article</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  has_many </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">comments</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">dependent</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">destroy</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">title</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln">
                    </span><span class="hljs-symbol"><span class="pln">length</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">minimum</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<h2 id="الاستيثاق-authentication-في-rails">
	الاستيثاق Authentication في Rails
</h2>

<p>
	إن كنت ترغب في نشر المدوّنة على الإنترنت، سيكون بإمكان أي شخص إضافة وتعديل وحذف المقالات والتعليقات فيها.
</p>

<p>
	يقدّم Rails نظام استيثاق HTTP بسيط يمكن استخدامه في التطبيقات البسيطة كتطبيقنا هذا.
</p>

<p>
	سنحتاج في المتحكّم <code>ArticlesController</code> إلى وسيلة لمنع وصول الشخص غير المستوثق منه إلى الأحداث التي يتضمّنها هذا المتحكّم، ويمكن استخدام تابع <code>http_basic_authenticate_with</code> لتحقيق ذلك.
</p>

<p>
	ولاستخدام نظام الاستثياق سنقوم بالإفصاح عنه في بداية ملف المتحكّم <code>ArticlesController in app/controllers/articles_controller.rb</code> وسنستوثق من جميع الأحداث المتوفّرة في هذا المتحكّم عدا حدثي <code>index</code> و<code>show</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5331_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">ArticlesController</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationController</span></span></span></span><span class="pln">

  http_basic_authenticate_with </span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"dhh"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">password</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"secret"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="kwd">except</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">index</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">show</span></span><span class="pun">]</span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">index
    </span><span class="hljs-variable"><span class="lit">@articles</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">all
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-comment"><span class="com"># بقيّة الشيفرة ...</span></span>
</code></pre>

<p>
	كذلك سنسمح للمستخدمين المستوثق منهم فقط بحذف التعليقات، لذا أضف الشيفرة التالية إلى المتحكّم <code>CommentsController</code> في الملف <code>app/controllers/comments_controller.rb</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5331_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CommentsController</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationController</span></span></span></span><span class="pln">

  http_basic_authenticate_with </span><span class="hljs-symbol"><span class="pln">name</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"dhh"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">password</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"secret"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">only</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">destroy</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">create
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article_id</span></span><span class="pun">])</span><span class="pln">
    </span><span class="hljs-comment"><span class="com"># ...</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-comment"><span class="com"># بقيّة الشيفرة ...</span></span>
</code></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="24993" href="https://academy.hsoub.com/uploads/monthly_2017_09/challenge.png.deac7711740fd4f19d8847e2f8ed26a1.png" rel=""><img alt="challenge.png" class="ipsImage ipsImage_thumbnailed" data-fileid="24993" data-unique="fwep9fli4" src="https://academy.hsoub.com/uploads/monthly_2017_09/challenge.thumb.png.b1d27a4ecee541e56eef620f1fab9078.png"></a>
</p>

<p>
	جدير بالذكر أنّ هناك العديد من وسائل الاستيثاق في تطبيقات Rails، أشهرها <a href="https://github.com/plataformatec/devise" rel="external nofollow">Devise rails engine</a> و <a href="https://github.com/binarylogic/authlogic" rel="external nofollow">Authlogic</a>.
</p>

<h2 id="إطار-العمل-rails-ونظام-الترميز-utf-8">
	إطار العمل Rails ونظام الترميز UTF-8
</h2>

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

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

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

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

<ol>
<li>
		<p>
			<strong>محرر النصوص:</strong> تحفظ معظم محرّرات النصوص الملفات البرمجية بصيغة UTF-8، وإن لم يقم محرّر النصوص الذي تستخدمه في كتابة الشيفرات البرمجية بذلك، فقد ينتج عن ذلك تحوّل الحروف الخاصّة أو حروف اللغات الأخرى غير الإنكليزية إلى التحول في المتصفّح إلى أشكال معينية بداخلها علامة استفهام. ينطبق هذا الأمر كذلك على ملفات الترجمة i18n. تجدر الإشارة إلى أنّه تتيح معظم محررات النصوص التي لا تحفظ الملفات البرمجية بهذا الترميز افتراضيًّا (مثل Dreamweaver) إمكانية تغيير الترميز الافتراضي للملفات المحفوظة إلى نظام UTF-8، وننصح بالقيام بذلك.
		</p>
	</li>
	<li>
		<p>
			<strong>قاعدة البيانات:</strong> يحوّل Rails البيانات القادمة من قاعدة البيانات إلى ترميز UTF-8، ولكن إن لم يكن هذا نظام الترميز هذا مستخدمًا من طرف قاعدة البيانات فلن يكون بالإمكان تخزين جميع المحارف المدخلة من قبل المستخدم. فعلى سبيل المثال، إن كان نظام الترميز الداخلي لقاعدة البيانات هو Latin-1 وأدخل المستخدم كلمات باللغة الروسية أو العربية أو اليابانية، فستخسر البيانات إلى الأبد بمجرد دخولها إلى قاعدة البيانات. لذا ينصح دائمًا بتحويل نظام الترميز الداخلي في قاعدة البيانات إلى نظام UTF-8.
		</p>
	</li>
</ol>
<h3 id="المصدر">
	المصدر:
</h3>

<p>
	<a href="http://guides.rubyonrails.org/getting_started.html" rel="external nofollow">توثيقات Ruby on Rails</a>.
</p>
]]></description><guid isPermaLink="false">533</guid><pubDate>Sun, 10 Sep 2017 10:14:47 +0000</pubDate></item><item><title>&#x627;&#x644;&#x646;&#x645;&#x627;&#x630;&#x62C; Models &#x641;&#x64A; Rails - &#x62A;&#x639;&#x62F;&#x64A;&#x644; &#x648;&#x62D;&#x630;&#x641; &#x627;&#x644;&#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; - &#x646;&#x645;&#x627;&#x630;&#x62C; &#x627;&#x644;&#x62A;&#x639;&#x644;&#x64A;&#x642;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/ruby/rails/%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-models-%D9%81%D9%8A-rails-%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D9%88%D8%AD%D8%B0%D9%81-%D8%A7%D9%84%D9%85%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-r532/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_09/59bd436c69a0a_main2(5).png.826531575f8da24b171e0c509e59898d.png" /></p>

<p>
	تحدّثنا في <a href="https://academy.hsoub.com/programming/ruby/rails/%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-models-%D9%81%D9%8A-rails-%D8%A5%D9%86%D8%B4%D8%A7%D8%A4%D9%87%D8%A7-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9%D9%87%D8%A7-%D8%AD%D9%81%D8%B8-%D8%A7%D9%84%D9%85%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r531/" rel="">الجزء السابق</a> من هذه <a href="https://academy.hsoub.com/tags/ruby%20on%20rails%20101/" rel="">السلسلة</a> عن النماذج في إطار العمل Ruby on Rails وتعرّفنا على طريقة إنشائها والتعامل معها من خلال كتابة الشيفرة المسؤولة عن حفظ المقالة الجديدة في قاعدة البيانات.
</p>

<p>
	في الجزء الثاني من هذا الموضوع سنتعلّم كيفية ربط نموذجين مع بعضهما البعض من خلال إنشاء نموذج جديد خاصّ بالتعليقات. ولكن قبل ذلك سنكمل ما بدأناه في الدروس السابقة من السلسلة في بناء عمليات “CRUD” حيث غطّينا سابقًا عمليتي الإنشاء Create و القراءة Read، وسنغطي اليوم العمليتين المتبقّيتين وهما التحديث Update والحذف Destroy.
</p>

<h3 id="تحديث-المقالات">
	تحديث المقالات
</h3>

<p>
	الخطوة الأولى في عملية تحديث المقالات هي إضافة حدث <code>edit</code> إلى المتحكم <code>ArticlesController</code> بين حدثي <code>new</code> و <code>create</code> وكما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<span class="kwd">def</span><span class="pln"> new
  </span><span class="lit">@article</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Article</span><span class="pun">.</span><span class="pln">new
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> edit
  </span><span class="lit">@article</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Article</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">params</span><span class="pun">[:</span><span class="pln">id</span><span class="pun">])</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> create
  </span><span class="lit">@article</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Article</span><span class="pun">.</span><span class="pln">new</span><span class="pun">(</span><span class="pln">article_params</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">save
    redirect_to </span><span class="lit">@article</span><span class="pln">
  </span><span class="kwd">else</span><span class="pln">
    render </span><span class="str">'new'</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	سيتضمن العرض استمارة مشابهة لتلك التي استخدمناها في إنشاء المقالات الجديدة. أنشئ ملفًّا باسم <code>app/views/articles/edit.html.erb</code> وأضف إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">Edit article</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> form_for</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">f</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">

  </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">any</span><span class="pun">?</span><span class="pln"> %&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"error_explanation"</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
        </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> pluralize</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">count</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"error"</span></span><span class="pun">)</span><span class="pln"> %&gt;</span></span><span class="pln"> prohibited
        this article from being saved:
      </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
        </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">full_messages</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">each</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">msg</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
          </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> msg %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="pln">
        </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">div</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">

  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">title %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_field </span><span class="pun">:</span><span class="pln">title %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">text %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_area </span><span class="pun">:</span><span class="pln">text %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">submit %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Back'</span><span class="pun">,</span><span class="pln"> articles_path %&gt;</span></span></span>
</code></pre>

<p>
	سنوجّه الاستمارة هذه المرة إلى حدث <code>update</code> والذي لم نقم بتعريفه حتى الآن.
</p>

<p>
	يؤدي تمرير كائن المقالة للتابع إلى إنشاء عنوان <code>url</code> لإرسال استمارة المقالة التي تم تعديلها، ومن خلال هذا الخيار نخبر Rails بأنّنا نرغب في أن يتم إرسال هذا النموذج من خلال فعل HTTP <code>PATCH</code> وهو أحد أفعال HTTP التي تستخدم في تحديث الموارد حسب بروتوكول REST.
</p>

<p>
	يمكن أن يكون المعامل الأول لـ <code>form_for</code> كائنًا، مثلًا <code>@articl</code>، والذي سيؤدي بالدالة المساعدة إلى ملء الاستمارة بالحقول التابعة للكائن، ويؤدي تمرير الرمز (<code>:article</code>) بنفس اسم المتغيّر من نوع <code>instance</code> (<code>@article</code>) إلى نفس النتيجة تلقائيًا.
</p>

<p>
	والآن سنقوم بإنشاء الحدث <code>update</code> في المتحكّم <code>app/controllers/articles_controller.rb</code> وسنضيفه بين حدث <code>create</code> والتابع ذي المحدّد الخاصّ <code>private</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">create
  </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pun">(</span><span class="pln">article_params</span><span class="pun">)</span><span class="pln">

  </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">save
    redirect_to </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln">
    render </span><span class="hljs-string"><span class="str">'new'</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">update
  </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">id</span></span><span class="pun">])</span><span class="pln">

  </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">update</span><span class="pun">(</span><span class="pln">article_params</span><span class="pun">)</span><span class="pln">
    redirect_to </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln">
    render </span><span class="hljs-string"><span class="str">'edit'</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

</span><span class="kwd">private</span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">article_params
    </span><span class="kwd">params</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">require</span></span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article</span></span><span class="pun">).</span><span class="pln">permit</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">title</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">text</span></span><span class="pun">)</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span>
</code></pre>

<p>
	يستخدم الحدث <code>update</code> عندما ترغب في تحديث سجل موجود في قاعدة البيانات، ويستقبل هذا الحدث جدول تقطيع <code>hash</code> يحتوي الخصائص التي ترغب في تحديثها. وكما سبق، في حال وجود خطأ في عملية التحديث سنعرض الاستمارة على المستخدم من جديد.
</p>

<p>
	سنستخدم التابع <code>article_params</code> الذي عرّفناه في وقت سابق للحدث <code>create</code>.
</p>

<p>
	لا حاجة لتمرير جميع الخصائص لغرض تحديثها، فعلى سبيل المثال، إن تم استدعاء <code>@article.update(title: 'A new title'</code>) فسيقوم Rails بتحديث خاصية العنوان فقط، ويترك باقي الخصائص دون تعديل.
</p>

<p>
	أخيرًا، نرغب في عرض رابط إلى الحدث <code>edit</code> في الصفحة التي نعرض فيها قائمة المقالات، لذا توجّه إلى الملف <code>app/views/articles/index.html.erb</code> وأضف الرابط ليظهر إلى جانب رابط “Show”:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">table</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">tr</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">Title</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">Text</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">th</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">colspan</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"2"</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">tr</span></span><span class="tag">&gt;</span></span><span class="pln">

  </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="lit">@articles</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">each</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">article</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">tr</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> article</span><span class="pun">.</span><span class="pln">title %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> article</span><span class="pun">.</span><span class="pln">text %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Show'</span><span class="pun">,</span><span class="pln"> article_path</span><span class="pun">(</span><span class="pln">article</span><span class="pun">)</span><span class="pln"> %&gt;</span></span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Edit'</span><span class="pun">,</span><span class="pln"> edit_article_path</span><span class="pun">(</span><span class="pln">article</span><span class="pun">)</span><span class="pln"> %&gt;</span></span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">tr</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">table</span></span><span class="tag">&gt;</span></span>
</code></pre>

<p>
	سنضيف كذلك رابطًا إلى قالب <code>app/views/articles/show.html.erb</code> ليظهر رابط “Edit” في صفحة المقالة أيضًا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs r"><span class="hljs-keyword"><span class="pun">...</span></span><span class="pln">
</span><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-string"><span class="str">'Edit'</span></span><span class="pun">,</span><span class="pln"> edit_article_path</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%&gt;</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-string"><span class="str">'Back'</span></span><span class="pun">,</span><span class="pln"> articles_path </span><span class="pun">%&gt;</span></code></pre>

<p>
	هذا هو شكل تطبيقنا حتى هذه اللحظة:
</p>

<p style="text-align: center;">
	<img alt="index_action_with_edit_link.png" class="ipsImage ipsImage_thumbnailed" data-fileid="24992" data-unique="h87x8a1hj" src="https://academy.hsoub.com/uploads/monthly_2017_09/index_action_with_edit_link.png.fdee9be510805a2b44b6f43ad6e07307.png"></p>

<h3 id="استخدام-الملفات-الجزئية-partials-لإزالة-التكرار-من-العروض">
	استخدام الملفات الجزئية partials لإزالة التكرار من العروض
</h3>

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

<p>
	أنشئ ملفًّا جديدًا باسم <code>_form.html.erb</code> ضمن المسار <code>app/views/articles/</code> وأضف إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs xml"><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> form_for </span><span class="lit">@article</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">f</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">

  </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">any</span><span class="pun">?</span><span class="pln"> %&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"error_explanation"</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
        </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> pluralize</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">count</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"error"</span></span><span class="pun">)</span><span class="pln"> %&gt;</span></span><span class="pln"> prohibited
        this article from being saved:
      </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
        </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">.</span><span class="pln">full_messages</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">each</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">msg</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
          </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> msg %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="pln">
        </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">div</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">

  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">title %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_field </span><span class="pun">:</span><span class="pln">title %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">text %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_area </span><span class="pun">:</span><span class="pln">text %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">submit %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span>
</code></pre>

<p>
	لاحظ أننا لم نغيّر شيئًا باستثناء الإعلان عن التابع <code>form_for</code> وسبب استخدام هذه الأسلوب المختصر والبسيط في الإعلان عن التابع <code>form_for</code> للتعبير عن الاستمارتين هو أن <code>@article</code> عبارة عن مورد يرتبط بمجموعةٍ من مسارات RESTful، وبإمكان Rails أن يخمّن عنوان URI والتابع الذي يجب استخدامه.
</p>

<p>
	والآن لنقم بتحديث العرض <code>app/views/articles/new.html.erb</code> لاستخدام الملف الجزئي الذي أنشأناه وسنقوم بإعادة كتابة العرض من جديد وكما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">New article</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> render </span><span class="hljs-comment"><span class="str">'form'</span><span class="pln"> %&gt;</span></span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Back'</span><span class="pun">,</span><span class="pln"> articles_path %&gt;</span></span></span>
</code></pre>

<p>
	ثم قم بالأمر عينه في ملف العرض <code>app/views/articles/edit.html.erb</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">Edit article</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> render </span><span class="hljs-comment"><span class="str">'form'</span><span class="pln"> %&gt;</span></span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Back'</span><span class="pun">,</span><span class="pln"> articles_path %&gt;</span></span></span></code></pre>

<h3 id="حذف-المقالات">
	حذف المقالات
</h3>

<p>
	هذه هي العملية الأخيرة ضمن عمليات CRUD، وبحسب معايير REST فإن المسار الذي يؤدي إلى حذف المقالات وكما يظهر في مخرجات الأمر <code>bin/rails routes</code> هو:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-constant"><span class="pln">DELETE</span></span><span class="pln"> </span><span class="pun">/</span><span class="pln">articles</span><span class="pun">/</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">id</span></span><span class="pun">(.</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">format</span></span><span class="pun">)</span><span class="pln">      articles</span><span class="hljs-comment"><span class="com">#destroy</span></span></code></pre>

<p>
	يجب استخدام الفعل <code>DELETE</code> في المسار المسؤول عن حذف الموارد، أما في حال استخدام الفعل <code>GET</code> فسيكون بالإمكان إنشاء رابط خبيث كهذا الرابط مثلًا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs livecodeserver"><span class="tag">&lt;</span><span class="hljs-operator"><span class="tag">a</span></span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="hljs-string"><span class="atv">'http://example.com/articles/1/destroy'</span></span><span class="tag">&gt;</span><span class="pln">look </span><span class="hljs-keyword"><span class="pln">at</span></span><span class="pln"> this cat!</span><span class="tag">&lt;/</span><span class="hljs-operator"><span class="tag">a</span></span><span class="tag">&gt;</span></code></pre>

<p>
	سنستخدم التابع <code>delete</code> لحذف المصادر، وهذا المسار مرتبط بالحدث <code>destroy</code> ضمن المتحكّم <code>app/controllers/articles_controller.rb</code> والذي لم نقم بإنشائه بعد. عادة ما يكون التابع <code>destroy</code> التابع الأخير ضمن المتحكّم، وكما هو الحال مع بقية التوابع العامّة <code>public</code> يجب الإعلان عنه قبل أي توابع خاصّة أو محميّة <code>protected</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">destroy
  </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">id</span></span><span class="pun">])</span><span class="pln">
  </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">destroy

  redirect_to articles_path
</span><span class="hljs-keyword"><span class="kwd">end</span></span>
</code></pre>

<p>
	الصورة النهائية للمتحكّم <code>ArticleController</code> في الملف <code>app/controllers/articles_controller.rb</code> هي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">ArticlesController</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationController</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">index
    </span><span class="hljs-variable"><span class="lit">@articles</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">all
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">show
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">id</span></span><span class="pun">])</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="kwd">new</span><span class="pln">
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">edit
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">id</span></span><span class="pun">])</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">create
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="kwd">new</span><span class="pun">(</span><span class="pln">article_params</span><span class="pun">)</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">save
      redirect_to </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln">
      render </span><span class="hljs-string"><span class="str">'new'</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">update
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">id</span></span><span class="pun">])</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">update</span><span class="pun">(</span><span class="pln">article_params</span><span class="pun">)</span><span class="pln">
      redirect_to </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln">
      render </span><span class="hljs-string"><span class="str">'edit'</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">destroy
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">id</span></span><span class="pun">])</span><span class="pln">
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">destroy

    redirect_to articles_path
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="kwd">private</span><span class="pln">
    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">article_params
      </span><span class="kwd">params</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">require</span></span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article</span></span><span class="pun">).</span><span class="pln">permit</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">title</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">text</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يمكن استدعاء التابع <code>destroy</code> في كائنات التسجيلة النشطة Active Record عندما ترغب في حذفها من قاعدة البيانات. لاحظ أنّنا لسنا بحاجة لإضافة عرض خاص بهذا الحدث لأنّنا نعيد توجيه المستخدم إلى الحدث <code>index</code>.
</p>

<p>
	أخيرًا أضف رابط ‘Destroy’ إلى القالب <code>app/views/articles/index.html.erb</code> لنربط كل الصفحات مع بعضها البعض.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">Listing Articles</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'New article'</span><span class="pun">,</span><span class="pln"> new_article_path %&gt;</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">table</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">tr</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">Title</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">Text</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">th</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">colspan</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"3"</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">th</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">tr</span></span><span class="tag">&gt;</span></span><span class="pln">

  </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="lit">@articles</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">each</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">article</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">tr</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> article</span><span class="pun">.</span><span class="pln">title %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> article</span><span class="pun">.</span><span class="pln">text %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Show'</span><span class="pun">,</span><span class="pln"> article_path</span><span class="pun">(</span><span class="pln">article</span><span class="pun">)</span><span class="pln"> %&gt;</span></span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Edit'</span><span class="pun">,</span><span class="pln"> edit_article_path</span><span class="pun">(</span><span class="pln">article</span><span class="pun">)</span><span class="pln"> %&gt;</span></span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Destroy'</span><span class="pun">,</span><span class="pln"> article_path</span><span class="pun">(</span><span class="pln">article</span><span class="pun">),</span></span><span class="pln">
              method</span><span class="pun">:</span><span class="pln"> </span><span class="pun">:</span><span class="kwd">delete</span><span class="pun">,</span><span class="pln">
              data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> confirm</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-comment"><span class="str">'Are you sure?'</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> %&gt;</span></span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">td</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">tr</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">table</span></span><span class="tag">&gt;</span></span></code></pre>

<p>
	استخدمنا هنا التابع <code>link_to</code> بطريقة مختلفة، حيث مررّنا اسم المسار كمعامل ثانٍ، ثمّ مرّرنا الخيارات الأخرى بعد ذلك. تستخدم الخيارات <code>method: :delete</code> و<code>data: { confirm: 'Are you sure?' }</code> كخصائص HTML5 بحيث يؤدي الضغط على الرابط إلى عرض مربع حوار للتأكد من رغبة المستخدم في حذف المقالة، ثم إرسال الرابط باستخدام التابع <code>delete</code>.
</p>

<p>
	تتمّ تعملية التحقّق هذه بواسطة ملف JavaScript الذي يحمل الاسم <code>rails-ujs</code> والموجود بصورة افتراضية في مخطط التطبيق (<code>app/views/layouts/application.html.erb</code>)، وفي حال عدم وجود هذا الملف لن يظهر مربع الحوار التأكيدي للمستخدم.
</p>

<p>
	تهانينا أصبح بإمكانك الآن إنشاء وعرض وسرد وتحديث وحذف المقالات في مدوّنتك.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong><br>
			بصورة عامة يشجّع Rails على استخدام كائنات الموارد resources objects بدلًا من كتابة المسارات يدويًا.
		</p>
	</div>
</blockquote>

<h2 id="إضافة-النموذج-الخاص-بالتعليقات">
	إضافة النموذج الخاصّ بالتعليقات
</h2>

<p>
	سنقوم الآن بإنشاء نموذج جديد في تطبيقنا هذا ستكون وظيفته التعامل مع التعليقات.
</p>

<h3 id="إنشاء-النموذج">
	إنشاء النموذج
</h3>

<p>
	لإنشاء النموذج الخاص بالتعليقات سنتبع الأسلوب السابق نفسه وذلك باستخدام أداة المولّد لإنشاء نموذج يحمل الاسم Comment ويمثّل مرجعًا إلى المقالة. اكتب الأمر التالي في سطر الأوامر:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs vhdl"><span class="pln">$ bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-keyword"><span class="pln">generate</span></span><span class="pln"> model </span><span class="typ">Comment</span><span class="pln"> commenter</span><span class="pun">:</span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">body</span></span><span class="pun">:</span><span class="pln">text article</span><span class="pun">:</span><span class="pln">references</span></code></pre>

<p>
	سينشئ هذا الأمر أربعة ملفات:
</p>

<p>
	الملف Purpose
</p>

<center>
	<table border="1"><tbody>
<tr>
<td style="background-color: rgb(146, 14, 27); padding: 5px 10px; text-align: center; color: white;">
					الملف/المجلد
				</td>
				<td style="background-color: rgb(146, 14, 27); padding: 5px 10px; text-align: center; color: white;">
					الوظيفة
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					db/migrate/20140120201010_create_comments.rb
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					ملف التهجير المسؤول عن إنشاء جدول التعليقات في قاعدة البيانات (سيحمل اسم الملف لديك ختمًا زمنيًا مختلفًا)
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					app/models/comment.rb
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					النموذج الخاص بالتعليقات
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					test/models/comment_test.rb
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					ملف الاختبارات الخاص بنموذج التعليقات
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					test/fixtures/comments.yml
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					نماذج تعليقات تستخدم في إجراء الاختبارات
				</td>
			</tr>
</tbody></table>
</center>

<p>
	لنلق نظرة في البداية على ملف <code>app/models/comment.rb</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Comment</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  belongs_to </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	كما تلاحظ فمحتوى هذا الملف مشابه لنموذج <code>Article</code> الذي أنشأناه سابقًا، والفارق الوحيد هو السطر <code>belongs_to :article</code> والذي ينشئ رابطًا بين النموذجين، وسنتحدّث عن الروابط بعد قليل.
</p>

<p>
	أما الكلمة المفتاحية (<code>:references</code>) ضمن الأمر الذي قمنا بتنفيذه في سطر الأوامر، فهي نوع خاص من البيانات بالنسبة للنماذج. تنشئ هذه الكلمة المفتاحية عمودًا في الجدول الموجود في قاعدة البيانات يحمل اسم النموذج الذي تمّ تمريره إلى هذه الكلمة مع إضافة <code>_id</code> والذي يمثّل عددًا صحيحًا. ستتضح الأمور أكثر بالنسبة إليك إن تفحّصت ملف <code>db/schema.rb</code> أدناه.
</p>

<p>
	قام Rails - بالإضافة إلى إنشاء النموذج - بإنشاء تهجير وظيفته إنشاء الجدول المقابل للنموذج في قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="pln">
</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CreateComments</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ActiveRecord</span><span class="pun">::</span><span class="typ">Migration</span></span></span><span class="pun">[</span><span class="lit">5.0</span><span class="pun">]</span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">change
    create_table </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">comments</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">t</span><span class="pun">|</span><span class="pln">
      t</span><span class="pun">.</span><span class="kwd">string</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">commenter</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">text </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">body</span></span><span class="pln">
      t</span><span class="pun">.</span><span class="pln">references </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">foreign_key</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pln">

      t</span><span class="pun">.</span><span class="pln">timestamps
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	يُنشئ السطر <code>t.references</code> عمودًا من نوع <code>integer</code> باسم <code>article_id</code> إضافة إلى فهرس index خاص بهذا العمود وقيد مفتاح خارجي Foreign Key Constraint والذي يشير إلى عمود <code>id</code> في جدول المقالات.
</p>

<p>
	والآن نفذ التهجير باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">bin</span><span class="pun">/</span><span class="pln">rails </span><span class="hljs-symbol"><span class="pln">db</span><span class="pun">:</span></span><span class="pln">migrate</span></code></pre>

<p>
	ينفّذ Rails التهجيرات غير المنفّذة فقط؛ لذا ستكون نتيجة الأمر التالي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs asciidoc"><span class="hljs-header"><span class="pun">==</span><span class="pln">  </span><span class="typ">CreateComments</span><span class="pun">:</span><span class="pln"> migrating </span><span class="pun">=================================================</span></span><span class="pln">
</span><span class="hljs-bullet"><span class="pun">--</span><span class="pln"> </span></span><span class="pln">create</span><span class="hljs-emphasis"><span class="pln">_table</span><span class="pun">(:</span><span class="pln">comments</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">0.0115s</span><span class="pln">
</span><span class="pun">==</span><span class="pln">  </span><span class="typ">CreateComments</span><span class="pun">:</span><span class="pln"> migrated </span><span class="pun">(</span><span class="lit">0.0119s</span><span class="pun">)</span><span class="pln"> </span><span class="pun">========================================</span></span></code></pre>

<h3 id="ربط-النماذج-مع-بعضها-البعض">
	ربط النماذج مع بعضها البعض
</h3>

<p>
	تسهّل روابط التسجيلة النشطة تكوين العلاقات بين النماذج، وفي حالتنا هذه سنُنشئ علاقة بين جدولي التعليقات والمقالات، ولو فكّرنا في طبيعة العلاقة التي تربط بينهما فسنجد أنه:
</p>

<ul>
<li>
		ينتمي كل تعليق إلى مقالة واحدة.
	</li>
	<li>
		تمتلك المقالة الواحدة العديد من التعليقات.
	</li>
</ul>
<p>
	يستخدم Rails صياغة مشابهة للربط بين النماذج، وقد شاهدنا في نموذج <code>Comment</code> في الملف <code>app/models/comment.rb</code> الشيفرة المسؤولة عن ربط كل تعليق بمقالة واحدة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Comment</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  belongs_to </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	سنحتاج الآن إلى تكوين الجانب الثاني من الرابطة، أي ربط المقالات بالتعليقات، لذا توجّه إلى الملف <code>app/models/article.rb</code> وعدّله بالصورة التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Article</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationRecord</span></span></span></span><span class="pln">
  has_many </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">comments</span></span><span class="pln">
  validates </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">title</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">presence</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">true</span></span><span class="pun">,</span><span class="pln">
                    </span><span class="hljs-symbol"><span class="pln">length</span><span class="pun">:</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">minimum</span><span class="pun">:</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	والآن أصبح النموذجان مرتبطين مع بعضهما البعض تلقائيًا، فعلى سبيل المثال، في حال كان لدينا متغيّر <code>@article</code> والذي يمثّل مقالة معيّنة، يمكن استدعاء جميع التعليقات المرتبطة بتلك المقالة على هيئة مصفوفة وذلك من خلال <code>@article.comments</code>.
</p>

<h3 id="إضافة-مسار-خاص-بالتعليقات">
	إضافة مسار خاص بالتعليقات
</h3>

<p>
	كما هو الحال مع متحكم <code>welcome</code> سنحتاج إلى إضافة مسار نحدّد من خلاله العنوان الذي نرغب في استخدامه لمشاهدة التعليقات؛ لذا افتح ملف <code>config/routes.rb</code> مرة أخرى، وعدّله كما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="pln">resources </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">articles</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln">
  resources </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">comments</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	بهذه الطريقة تصبح التعليقات بمثابة موارد مضمّنة في المقالات، وهذه الطريقة هي جزء من العلاقة الهرمية التي تنشأ بين المقالات والتعليقات.
</p>

<h3 id="إنشاء-المتحكم-الخاص-بالتعليقات">
	إنشاء المتحكّم الخاصّ بالتعليقات
</h3>

<p>
	بعد أن انتهينا من إعداد النموذج، أصبح بإمكاننا الآن إنشاء المتحكّم الخاص بالتعليقات، وسنستخدم أداة المولّد كما فعلنا سابقًا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="pln">
</span><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">bin</span><span class="pun">/</span><span class="pln">rails generate controller </span><span class="hljs-constant"><span class="typ">Comments</span></span></code></pre>

<p>
	سينشئ هذا الأمر خمسة ملفات إضافة إلى مجلّد فارغ:
</p>

<center>
	<table border="1"><tbody>
<tr>
<td style="background-color: rgb(146, 14, 27); padding: 5px 10px; text-align: center; color: white;">
					الملف/المجلد
				</td>
				<td style="background-color: rgb(146, 14, 27); padding: 5px 10px; text-align: center; color: white;">
					الوظيفة
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					app/controllers/comments_controller.rb
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					المتحكّم الخاص بالتعليقات
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					/app/views/comments
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					يتم تخزين العروض الخاصّة بالتعليقات في هذا المجلد
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					test/controllers/comments_controller_test.rb
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					ملف الاختبار الخاصّ بالمتحكّم
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					app/helpers/comments
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					الملف الخاصّ بمساعد العرض
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					app/assets/javascripts/comments.coffee
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					ملف CoffeScript الخاصّ بالمتحكّم
				</td>
			</tr>
<tr>
<td style=" padding: 5px 10px; text-align: left;">
					app/assets/stylesheets/comments.scss
				</td>
				<td style=" padding: 5px 10px; text-align: right;">
					أوراق الأنماط المتتالية CSS الخاصّة بالمتحكّم
				</td>
			</tr>
</tbody></table>
</center>

<p>
	كما هو الحال مع أي مدوّنة، فإن القرّاء سيكتبون تعليقاتهم بعد قراءة المقالة مباشرة، وبعد أن يرسلوا تعليقاتهم يتم توجيههم إلى صفحة عرض المقالة ليتمكّنوا من مشاهدة التعليقات. وستكون وظيفة المتحكّم <code>CommentsController</code> هي توفير التوابع اللازمة لإنشاء التعليقات وحذف التعليقات المزعجة حال وصولها.
</p>

<p>
	سنقوم أولًا بتعديل قالب عرض المقالات <code>app/views/articles/show.html.erb</code> لنتمكن من إضافة تعليق جديد:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Title:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">title %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Text:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">text %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">Add a comment:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> form_for</span><span class="pun">([</span><span class="lit">@article</span><span class="pun">,</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">comments</span><span class="pun">.</span><span class="pln">build</span><span class="pun">])</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">f</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">commenter %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_field </span><span class="pun">:</span><span class="pln">commenter %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">body %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_area </span><span class="pun">:</span><span class="pln">body %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">submit %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Edit'</span><span class="pun">,</span><span class="pln"> edit_article_path</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">)</span><span class="pln"> %&gt;</span></span></span><span class="pln"> |
</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Back'</span><span class="pun">,</span><span class="pln"> articles_path %&gt;</span></span></span>
</code></pre>

<p>
	ستضيف الشيفرة السابقة استمارة إلى صفحة عرض المقالات يمكن من خلالها إضافة تعليق جديد من خلال استدعاء الحدث <code>create</code> ضمن المتحكّم <code>CommentsController</code>. ويستخدم الاستدعاء <code>form_for</code> مصفوفة ستعمل على إنشاء مسار متداخل nested route مثل: <code>/articles/1/comments</code>.
</p>

<p>
	لنجرِ الآن التعديلات اللازمة على الحدث <code>create</code> في الملفّ <code>app/controllers/comments_controller.rb</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs ruby"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">CommentsController</span></span><span class="pln"> </span><span class="hljs-inheritance"><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-parent"><span class="typ">ApplicationController</span></span></span></span><span class="pln">
  </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">create
    </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-constant"><span class="typ">Article</span></span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="kwd">params</span><span class="pun">[</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">article_id</span></span><span class="pun">])</span><span class="pln">
    </span><span class="hljs-variable"><span class="lit">@comment</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">.</span><span class="pln">comments</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">comment_params</span><span class="pun">)</span><span class="pln">
    redirect_to article_path</span><span class="pun">(</span><span class="hljs-variable"><span class="lit">@article</span></span><span class="pun">)</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">

  </span><span class="kwd">private</span><span class="pln">
    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span></span><span class="pln">comment_params
      </span><span class="kwd">params</span><span class="pun">.</span><span class="hljs-keyword"><span class="kwd">require</span></span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">comment</span></span><span class="pun">).</span><span class="pln">permit</span><span class="pun">(</span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">commenter</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-symbol"><span class="pun">:</span><span class="pln">body</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">end</span></span></code></pre>

<p>
	ستتعقّد الأمور هنا قليلًا وذلك بسبب التداخل nesting الحاصل بين المسارات، إذ في كل مرة يتمّ فيها طلب تعليق معيّن يجب أن يتابع ذلك الطلب المقالة التي يرتبط بها هذا التعليق، وبالتالي استدعاء التابع <code>find</code> في نموذج <code>Article</code> والمسؤول عن اختيار المقالة المطلوبة حسب المعرّف المحدّد في المسار.
</p>

<p>
	بالإضافة إلى ذلك، استفدنا من بعض التوابع التي تقدّمها عملية الربط بين النموذجين، فقد استخدمنا التابع <code>create</code> على <code>@article.comments</code> لإنشاء التعليق وحفظه، وسيؤدي هذا إلى ربط التعليق الجديد بالمقالة المحدّدة.
</p>

<p>
	وبعد إنشاء التعليق الجديد نعيد توجيه المستخدم إلى المقالة الأصلية باستخدام الدالة المساعد <code>article_path(@article)</code>. وكما شاهدنا تستدعي هذه الدالة الحدث <code>show</code> ضمن المتحكّم <code>ArticlesController</code> والذي يعمل بدوره على تصيير القالب <code>show.html.erb</code>، وهو المكان الذي نرغب أن تظهر التعليقات فيه؛ لذا سنقوم بإجراء التعديلات اللازمة على الملف <code>app/views/articles/show.html.erb</code>.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3372_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Title:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">title %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Text:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">text %&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">Comments</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">comments</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">each</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">comment</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Commenter:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> comment</span><span class="pun">.</span><span class="pln">commenter %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">

  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">Comment:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">strong</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> comment</span><span class="pun">.</span><span class="pln">body %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">Add a comment:</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> form_for</span><span class="pun">([</span><span class="lit">@article</span><span class="pun">,</span><span class="pln"> </span><span class="lit">@article</span><span class="pun">.</span><span class="pln">comments</span><span class="pun">.</span><span class="pln">build</span><span class="pun">])</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">do</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">f</span><span class="pun">|</span><span class="pln"> %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">commenter %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_field </span><span class="pun">:</span><span class="pln">commenter %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">label </span><span class="pun">:</span><span class="pln">body %&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">br</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">text_area </span><span class="pun">:</span><span class="pln">body %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">submit %&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="vbscript"><span class="pun">&lt;%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">end</span></span><span class="pln"> %&gt;</span></span><span class="pln">

</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Edit'</span><span class="pun">,</span><span class="pln"> edit_article_path</span><span class="pun">(</span><span class="lit">@article</span><span class="pun">)</span><span class="pln"> %&gt;</span></span></span><span class="pln"> |
</span><span class="vbscript"><span class="pun">&lt;%=</span><span class="pln"> link_to </span><span class="hljs-comment"><span class="str">'Back'</span><span class="pun">,</span><span class="pln"> articles_path %&gt;</span></span></span>
</code></pre>

<p>
	أصبح بإمكانك الآن إضافة المقالات والتعليقات إلى مدوّنتك وعرضها في الأماكن الصحيحة.
</p>

<p>
	في الدرس القادم سنكمل العمل على التعليقات، حيث سنستخدم الملفات الجزئية لترتيب القوالب أوّلًا، ثم نضيف إمكانية حذف التعليقات من قاعدة البيانات، وفي الختام سنتطرّق إلى عملية الاستيثاق Authentication بصورة سريعة ومبسّطة.
</p>

<h3 id="المصدر">
	المصدر:
</h3>

<p>
	<a href="http://guides.rubyonrails.org/getting_started.html" rel="external nofollow">توثيقات Ruby on Rails</a>.
</p>
]]></description><guid isPermaLink="false">532</guid><pubDate>Sat, 16 Sep 2017 15:30:18 +0000</pubDate></item></channel></rss>
