سه شنبه, ۱۸ اردیبهشت, ۱۴۰۳ / 7 May, 2024
مجله ویستا

یکپارچگی در مدیریت توسعه وب


یکپارچگی در مدیریت توسعه وب

حفظ سلامت داده ها با استفاده از Rails و PostgreSQL

NoSQL عبارت جهانشمول جدیدی که برای دیتابیس‌های غیررابطه‌ای استفاده می‌شود، در میان توسعه‌دهندگان وب خیلی جا نیفتاده است. البته اطلاق NoSQL برای تعریف آنها کمی بی‌انصافی است و شامل فناوری‌های مختلفی می‌شود. با وجود این، تفاوت‌های پایه‌ای میان این دو نوع دیتابیس وجود دارد. همان‌طور که از نام NoSQL‌ مشخص است، در این دیتابیس‌ها خبری از زبان SQL نیست و هر یک از آنها از زبان مشابه SQL خود استفاده می‌کند یا یک API شی‌ءگرا دارد.

یکی دیگر از این تفاوت‌ها، نبود جداول دوبعدی است. در حالی که دیتابیس‌های SQL منحصرا با این نوع جداول کار می‌کنند، دیتابیس‌های NoSQL به حالت جفت‌های نام ـ متغیر یا اشیای Hash داده را در خود ذخیره می‌کنند. در نهایت، دیتابیس‌های NoSQL قابلیت‌هایی که توسعه در دیتابیس‌های رابطه‌ای را ممکن می‌کند، ندارند.

بی‌شک انعطاف‌پذیری دیتابیس‌های NoSQL در سطوح مختلف جذاب است. درست همانند کارکرد با زبان‌های داینامیک که نیازی به تعریف متغیر پیش از استفاده از آنها وجود ندارد، می‌توان داده‌ها را در دیتابیس ذخیره‌کرد، بی‌آن که ساختاری برای دیتابیس تعریف کرده باشیم. مثلا اگر بخواهیم فیلد جدیدی برای فرد تعریف کنیم، کافی است دیتای جدید را به سرور بفرستیم، از این به بعد دیتابیس حواسش به فیلد جدید خواهد بود.

هر چند موارد دیگری وجود دارد که می‌خواهیم دیتابیس سختگیری داشته باشیم و یکپارچگی داده‌هایمان را حفظ کنیم. مثلا می‌خواهیم مطمئن باشیم حتی اگر مشکلی در کار با برنامه وجود داشت، یا داده‌ای وارد شد که مجاز نبود، دیتابیس آن داده بد را ذخیره نکند. بررسی این اطلاعات در سمت سرور و نه فقط در سمت نرم‌افزار گزینه خوبی است؛ چرا که در مقابل داده خراب، سپر محافظ دیگری استفاده می‌شود.

Ruby On Rails، فریم‌ورک قدرتمند طراحی وب که به‌صورت پیش‌فرض از دیتابیس‌های زیادی پشتیبانی می‌کند، در وهله اول، به سمت MySQL متمایل است، اما کار با دیتابیس‌های بزرگ‌تری چون PostgreSQL برای این فریم‌ورک دشوار است؛ زیرا از کلیدهای خارجی پشتیبانی نمی‌کند.

برای بررسی امن بودن داده‌ها، بهتر است مکانیسم بررسی اطلاعاتی را در دیتابیس قرار دهیم و از سطح نرم‌افزار آن را بررسی کنیم. اضافه‌کردن پشتیبانی از کلیدهای خارجی و مکانیسم CHECK در PostgreSQL در ادامه مطلب آورده شده است.

● داده را در کجا چک کنیم؟

پیش از آن که وارد کد و پیاده‌سازی شویم، بهتر است نخست به این بپردازیم که کجا و چگونه داده را بررسی کنیم. همان طور که پیشتر اشاره شد، می‌توان داده را در دو سطح نرم‌افزار و دیتابیس بررسی کرد؛ هر چند برنامه‌نویسان تنبل‌تر ترجیح می‌دهند فقط در سطح نرم‌افزار و با قابلیت‌های پیش‌فرض Rails داده‌ها را بررسی کنند.

بررسی داده در سطح نرم‌افزار، مزایای خودش را دارد. پیاده‌سازی آسان‌تر خواهد شد و معمولا هم بدرستی کار می‌کند. به‌خصوص در محیط Rails می‌توان با یک زبان (Ruby)، اطلاعات لازم را در مدل قرار داد و بعد از آن استفاده کرد.

اما همان طور که پیشتر گفتیم، اگر اطلاعات را فقط در سطح نرم‌افزار بررسی کنیم، ممکن است این اتفاق رخ بدهد که اطلاعات مستقیما در دیتابیس تزریق شود و کار به هم بریزد. حتی اگر احتمال به هم ریخته شدن اطلاعات را بسیار اندک در نظر بگیریم، بازگشت و تعمیر این دیتابیس کار دشواری خواهد بود.

هر چند بسیاری از نرم‌افزارهای تحت وب این طور طراحی شده‌است و حفره امنیتی بزرگی وجود ندارد، اما این چیزی است که باید از آن اجتناب کرد.

البته روش دیگر، اشتباه بزرگ‌تری را رقم می‌زند؛ زیرا چک‌کردن فقط در محیط دیتابیس باعث مشکلات عظیم‌تری خواهد شد. مثلا فرض کنیم جدولی با محتوای NOT NULL در دیتابیس داریم، یعنی این فیلد نمی‌تواند مقدار NULL به‌خود بگیرد. اگر در مرحله نرم‌افزار جلوی خطا را نگیریم، اطلاعات خراب وارد دیتابیس می‌شود. هر چند دیتابیس خراب نشده، اما نرم‌افزار ممکن است پیام خطا بدهد و رفع این ایراد هم دشوار و گیج‌کننده خواهد بود.

بنابراین، هرقدر هم که کار دشوار و سختی باشد، بهترین روش برای جلوگیری از این اتفاقات، دوباره‌کاری در مرحله چک کردن اطلاعات است. ایجاد شرط هم داخل نرم‌افزار و هم داخل دیتابیس می‌تواند مشکلات را بخوبی حل کند. در Rails، client_side_validations می‌تواند قوانین مدل را گرفته و آنها را به‌صورت جاوااسکریپت درون فرم‌ها تعبیه کند.

● کلیدهای خارجی

با این پیش‌زمینه می‌توان فرض کرد که می‌خواهیم یک تقویم قرار ملاقات ساده بسازیم. می‌خواهیم افراد مختلف را بشناسیم.

هر یک از این افراد مشخصاتی دارند (نام، نام خانوادگی، آدرس ایمیل و شماره تلفن) و قرارهایشان را نیز باید ثبت کنیم (که زمان و تاریخ آنها ثبت خواهد شد، همچنین فرد مقابل که قرار است با او جلسه گذاشته شود نیز نامش باید درج شود،

یک فیلد توضیحات که می‌توان موضوع جلسه را در آن مشخص کرد.)

در سطح دیتابیس، با جدول ساده‌ای روبه‌رو هستیم:

CREATE TABLE People

,id SERIAL)

, first_name TEXT NOT NULL

, last_name TEXT NOT NULL

, email TEXT NOT NULL

, phone TEXT NOT NULL

PRIMARY KEY(id)؛)

CREATE TABLE Appointments

, id SERIAL ,)

person_id INTEGER REFERENCES People NOT NULL

, notes TEXT NOT NULL

PRIMARY KEY(id)؛)

به عبارت REFERENCES People دقت کنید. این عبارت دو جدول را به‌یکدیگر متصل می‌کند. مثلا اگر بخواهیم اطلاعاتی را از جدول People حذف کنیم، با این خطا مواجه می‌شویم:‌

atf=# DELETE FROM People WHERE id = ۱;

ERROR: update or delete on table "people" violates foreign key

constraint "appointments_person_id_fkey" on table "appointments"

DETAIL: Key (id)=(۱) is still referenced from table "appointments".

از آنجا که Appointments.person_id کلید خارجی People.id است، سیستم پیغام خطا می‌دهد. این جور ارتباطات برای نرم‌افزار بسیار مفید خواهد بود. این یعنی اگر کسی در سیستم‌قرارها وارد شود، نمی‌توان آن را حذف کرد.

● پیاده‌سازی در Rails

اگر این جداول بخشی از یک نرم‌افزار تحت وب باشد که در Ruby On Rails‌ مشغول توسعه آنها هستیم، در این صورت می‌توان از database migration برای تولید آنها استفاده کرد.

class CreatePeopleAndAppointments « ActiveRecord::Migration

def change

create_table :people do |t|

t.string :first_name, :null =» false

t.string :last_name, :null =» false

t.string :email, :null =» false

t.string :phone, :null =» false

t.timestamps

end

create_table :appointments do |t|

t.integer :person_id, :null =» false

t.text :notes, :null =» false

t.timestamps

end

end

end

این فایل، ایجاد جداول را به عهده می‌گیرد، اما کلیدهای خارجی در آن وجود ندارد، به‌این منظور اگر رکوردی از People را حذف کنیم، ممکن است دیتابیس خراب شود. برای استفاده از کلیدهای خارجی، باید SQL صحیح را مستقیما به دیتابیس بفرستیم.

خوشبختانه روش ساده‌تری برای این کار وجود دارد. Foreigner gem که توسط برنامه‌نویس، Matthew Higgins نوشته شده است، می‌تواند با MySQL و PostgreSQL همخوان شود، و Syntax جدیدی ایجاد کرده است که می‌توان کلیدهای خارجی را در migrationها ایجاد یا حذف کرد. بعد از نصب این gem کافی است از دستوری مشابه دستور زیر استفاده کنیم:

class AddForeignKey « ActiveRecord::Migration

def up

add_foreign_key:appointments,:people

end

def down

remove_foreign_key:appointments,:people

end

end

نکته مهم این است که باید این پیاده‌سازی را در مدل Rails نیز انجام دهیم، در غیر این صورت امکان دارد اتفاقی رخ دهد و آن هم این است که مدل داده را قبول می‌کند، اما دیتابیس آن را انجام نمی‌دهد و errorعجیبی به کاربر نشان داده می‌شود.

حالا بیایید فرض کنیم هم‌اکنون پروژه‌ای زیر دست دارید، اما کلیدهای خارجی را در آن تعریف نکرده‌اید. برای تصحیح می‌توان یکی یکی جداول را بررسی، سپس کلیدهای خارجی آنها را تعریف کرد. اما Immigrant gem برای Rails خودش از مدل‌های Rails برای تشخیص کلیدهای خارجی استفاده می‌کند و نیازی به دوباره کاری در مرحله سرورها وجود نخواهد داشت. کافی است مدل‌های rails را تصحیح کرده، سپس از این gem استفاده کنید.

محمدرضا قربانی