دليل: إنشاء محرك تدوين باستخدام Node.js و MongoDB

Amine
02/09/2024

دليل شامل لإنشاء نظام مدونة باستخدام Node.js وMongoDB

في هذا الدرس المفصل، سنقوم بإنشاء نظام مدونة كامل باستخدام Node.js وMongoDB. سنغطي كل الجوانب بدءًا من إعداد المشروع وحتى إنشاء واجهة المستخدم الأمامية.

المتطلبات الأساسية

  • Node.js (الإصدار 14 أو أحدث) مثبت على جهازك
  • MongoDB (الإصدار 4 أو أحدث) مثبت ويعمل على جهازك
  • معرفة أساسية بـ JavaScript وNode.js وHTML/CSS
  • محرر نصوص مثل Visual Studio Code

الخطوة 1: إعداد المشروع

افتح Terminal أو Command Prompt وقم بتنفيذ الأوامر التالية:

mkdir blog-system
cd blog-system
npm init -y
npm install express mongoose body-parser ejs

هذه الأوامر ستقوم بإنشاء مجلد جديد للمشروع، وتهيئة مشروع Node.js، وتثبيت الحزم اللازمة.

الخطوة 2: هيكلة المشروع

قم بإنشاء الملفات والمجلدات التالية في مجلد المشروع:

blog-system/
  ├── models/
  │   └── Article.js
  ├── routes/
  │   └── articles.js
  ├── views/
  │   ├── index.ejs
  │   ├── show.ejs
  │   ├── new.ejs
  │   └── edit.ejs
  ├── public/
  │   └── style.css
  └── server.js

الخطوة 3: إعداد الخادم

افتح ملف server.js وأضف الكود التالي:

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const path = require('path');

const app = express();
const PORT = process.env.PORT || 3000;

// اتصال بقاعدة البيانات
mongoose.connect('mongodb://localhost/blog_db', { 
  useNewUrlParser: true, 
  useUnifiedTopology: true 
}).then(() => console.log('تم الاتصال بقاعدة البيانات'))
  .catch(err => console.error('خطأ في الاتصال بقاعدة البيانات:', err));

// إعداد المحرك
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

// الوسائط (Middleware)
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));

// المسارات
const articlesRoutes = require('./routes/articles');
app.use('/articles', articlesRoutes);

// الصفحة الرئيسية
app.get('/', (req, res) => {
  res.redirect('/articles');
});

// تشغيل الخادم
app.listen(PORT, () => {
  console.log(`الخادم يعمل على المنفذ ${PORT}`);
});

الخطوة 4: إنشاء نموذج المقالة

في ملف models/Article.js، أضف الكود التالي:

const mongoose = require('mongoose');

const ArticleSchema = new mongoose.Schema({
  title: { type: String, required: true },
  content: { type: String, required: true },
  author: { type: String, required: true },
  createdAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Article', ArticleSchema);

الخطوة 5: إنشاء المسارات (Routes)

في ملف routes/articles.js، أضف الكود التالي:

const express = require('express');
const router = express.Router();
const Article = require('../models/Article');

// عرض جميع المقالات
router.get('/', async (req, res) => {
  try {
    const articles = await Article.find().sort({ createdAt: 'desc' });
    res.render('index', { articles: articles });
  } catch (error) {
    res.status(500).render('error', { message: error.message });
  }
});

// صفحة إنشاء مقالة جديدة
router.get('/new', (req, res) => {
  res.render('new');
});

// إنشاء مقالة جديدة
router.post('/', async (req, res) => {
  try {
    const article = new Article({
      title: req.body.title,
      content: req.body.content,
      author: req.body.author
    });
    await article.save();
    res.redirect('/articles');
  } catch (error) {
    res.render('new', { error: error.message });
  }
});

// عرض مقالة واحدة
router.get('/:id', async (req, res) => {
  try {
    const article = await Article.findById(req.params.id);
    if (article == null) res.redirect('/');
    res.render('show', { article: article });
  } catch (error) {
    res.status(500).render('error', { message: error.message });
  }
});

// صفحة تعديل المقالة
router.get('/:id/edit', async (req, res) => {
  try {
    const article = await Article.findById(req.params.id);
    res.render('edit', { article: article });
  } catch (error) {
    res.redirect('/');
  }
});

// تحديث المقالة
router.post('/:id', async (req, res) => {
  try {
    const article = await Article.findById(req.params.id);
    article.title = req.body.title;
    article.content = req.body.content;
    article.author = req.body.author;
    await article.save();
    res.redirect(`/articles/${article.id}`);
  } catch (error) {
    res.render('edit', { article: article, error: error.message });
  }
});

// حذف المقالة
router.post('/:id/delete', async (req, res) => {
  try {
    await Article.findByIdAndDelete(req.params.id);
    res.redirect('/');
  } catch (error) {
    res.status(500).render('error', { message: error.message });
  }
});

module.exports = router;

الخطوة 6: إنشاء القوالب (Views)

قم بإنشاء الملفات التالية في مجلد views:

1. index.ejs:

<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>نظام المدونة</title>
  <link rel="stylesheet" href="/style.css">
</head>
<body>
  <h1>جميع المقالات</h1>
  <a href="/articles/new" class="btn">إنشاء مقالة جديدة</a>
  <% articles.forEach(article => { %>
    <div class="article-card">
      <h2><a href="/articles/<%= article.id %>"><%= article.title %></a></h2>
      <p>الكاتب: <%= article.author %></p>
      <p>تاريخ النشر: <%= article.createdAt.toLocaleDateString() %></p>
    </div>
  <% }) %>
</body>
</html>

2. show.ejs:

<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><%= article.title %></title>
  <link rel="stylesheet" href="/style.css">
</head>
<body>
  <h1><%= article.title %></h1>
  <p>الكاتب: <%= article.author %></p>
  <p>تاريخ النشر: <%= article.createdAt.toLocaleDateString() %></p>
  <div><%= article.content %></div>
  <a href="/articles/<%= article.id %>/edit" class="btn">تعديل</a>
  <form action="/articles/<%= article.id %>/delete" method="POST">
    <button type="submit" class="btn btn-danger">حذف</button>
  </form>
  <a href="/articles" class="btn">العودة إلى الصفحة الرئيسية</a>
</body>
</html>

3. new.ejs:

<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>إنشاء مقالة جديدة</title>
  <link rel="stylesheet" href="/style.css">
</head>
<body>
  <h1>إنشاء مقالة جديدة</h1>
  <form action="/articles" method="POST">
    <div>
      <label for="title">العنوان:</label>
      <input type="text" id="title" name="title" required>
    </div>
    <div>
      <label for="author">الكاتب:</label>
      <input type="text" id="author" name="author" required>
    </div>
    <div>
      <label for="content">المحتوى:</label>
      <textarea id="content" name="content" required></textarea>
    </div>
    <button type="submit" class="btn">نشر المقالة</button>
  </form>
  <a href="/articles" class="btn">العودة إلى الصفحة الرئيسية</a>
</body>
</html>

4. edit.ejs:

<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>تعديل المقالة</title>
  <link rel="stylesheet" href="/style.css">
</head>
<body>
  <h1>تعديل المقالة</h1>
  <form action="/articles/<%= article.id %>" method="POST">
    <div>
      <label for="title">العنوان:</label>
      <input type="text" id="title" name="title" value="<%= article.title %>" required>
    </div>
    <div>
      <label for="author">الكاتب:</label>
      <input type="text" id="author" name="author" value="<%= article.author %>" required>
    </div>
    <div>
      <label for="content">المحتوى:</label>
      <textarea id="content" name="content" required><%= article.content %></textarea>
    </div>
    <button type="submit" class="btn">تحديث المقالة</button>
  </form>
  <a href="/articles" class="btn">العودة إلى الصفحة الرئيسية</a>
</body>
</html>

الخطوة 7: إضافة تصميم CSS

قم بإنشاء ملف public/style.css لإضافة التنسيقات الأساسية:

body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
  text-align: right;
  direction: rtl;
}

h1, h2 {
  color: #333;
}

.btn {
  display: inline-block;
  padding: 10px 20px;
  margin: 10px 0;
  background-color: #007BFF;
  color: #fff;
  text-decoration: none;
  border-radius: 5px;
}

.btn-danger {
  background-color: #dc3545;
}

.article-card {
  background-color: #fff;
  border: 1px solid #ccc;
  padding: 20px;
  margin-bottom: 20px;
  border-radius: 5px;
}

label {
  display: block;
  margin-top: 10px;
}

input, textarea {
  width: 100%;
  padding: 10px;
  margin-top: 5px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

textarea {
  height: 200px;
}

الخاتمة

تهانينا! لقد قمت بإنشاء نظام مدونة بسيط باستخدام Node.js وMongoDB. لقد تعلمت كيفية:

  • إعداد مشروع Node.js.
  • إنشاء نموذج MongoDB للمقالات.
  • إنشاء مسارات Express للتعامل مع المقالات.
  • إنشاء قوالب EJS لعرض البيانات والتفاعل مع المستخدم.

يمكنك تطوير المشروع أكثر من خلال إضافة ميزات مثل تسجيل الدخول للمستخدمين، البحث في المقالات، أو تحسين تصميم الواجهة.

التعليقات

اترك تعليقاً