از چه ساختاری برای سرور مبتنی بر Ruby on Rails استفاده کنیم؟
تو این مقاله کاری به اینکه چرا از Ruby on Rails استفاده کنیم یا نکنیم ندارم و فقط میخوام ساختاری رو که تو برنامهم ترجیح میدم داشته باشم رو بنویسم و خیلی خوشحال میشم که پیشنهادهای شما رو هم در این رابطه بدونم.
همون طور که میدونیم RoR ازمعماری MVC استفاده میکنه و خیلی شمارو به سمتی هُل میده که شما هم از این معماری خارج نشین که مزایای خیلی خوبی داره: به راحتی میتونین کد بقیه رو بفهمین و دباگ کنین، تو این حالت میشه CLI های خیلی خوبه براش نوشت، تو کار تمیمی خیلی نگران نیستین که سایر همتیمیها از معماری خارج بشن و …
راستش من همیشه از اینکه این ساختار رو داشته باشم ناراضی بودم و همیشه خلاء یک لایهی دیگهرو احساس میکردم و Best Practice هایی که موجود بودن هم پیشنهاد میکنن که شما اکثر توابع خودتون رو تو Model ها بنویسین و اونهارو چاق کنین و Controller های لاغری داشته باشین. اما مشکلی که من داشتم این بود که یک سری منطقهای هستن که برای اجرا شدن نیاز دارن از چند مُدل استفاده کنن و توابع نمیتونن داخل یک مُدل باشن، پس یک لایهی دیگری رو نیاز داشتم که به اصطلاح Business Logic خودم رو تو اون بنویسم. پس یک لایه به نام services به کد من اضافه شد.
برای پیادهسازی لایه Service از ساختارهای مختلفی میشه استفاده کرد. من یه مدت از wisper استفاده میکردم. اما یه سری مشکلات اساسی داشت که باعث شد کاملا کنارش بذارم و حتی الان هم جاهایی که میبینم از این ساختار استفاده شده refactor میکنم.
تو نوشتن API یکی از چیزهایی که من آرزو داشتم داشته باشم اعتبارسنجی پارامترهایی ورودی بود. میدیدم بچهها از grape برای نوشتن API استفاده میکنن و این ويژگی تو این جِم هست و چون من از این جِم خوشم نمیومد، سعی داشتم که این نیازم رو جور دیگهای برطرف کنم. جم grape کار اعتبارسنجی رو تو لایهی view انجام میده و البته مزیایا خودش رو داره، اما من از چاق شدن کنترولرها شاکی بودم و دنبال جایگزین برای این جِم بودم تا اینکه active interaction رو دیدم.
اگر بخوام نقاط قوت این جِم رو بگم: ۱.اعتبارسنجی پارامترهای ارسال شده ۲.جلوگیری از داشتن کنترولرهای چاق(کد زیاد) ۳. افزایش قابلیت استفاده مجدد سرویسها ۴. مدیریت مناسب خطاها ۵. پشتیبانی از localization که میشه پیغامهای فارسی مناسبی ایجاد کرد. ۶…(الان دیگه چیزی تو ذهنم نیست)
در ادامه مثالی از یک سرویس برای ساخت کامنت آمده است:
class Social::Api::V1::Comment::Create < ActiveInteraction::Base
object :current_user, class: User
string :post_uid
string :body def execute
post = ::Post.find_by! uid: post_uid comment = ::Comment.build_from post, current_user.id, body
comment.save return errors.merge!(comment.errors) unless comment.valid? comment
end
end
و نحوهی استفاده از سرویس تعریف شده در داخل کنترلر:
class Social::Api::V1::CommentController < ApplicationController
before_action :authorize? def create
permitted = params.permit(:post_uid, :parent_id, :body)
.merge(current_user: @current_user)
create = Social::Api::V1::Comment::Create.run(permitted)
return render
json: create.errors.full_messages,
status: BAD_REQUEST unless create.valid? @comment = create.result
render :show, status: CREATED
end
end