কম্পিউটার

Vue, Vuex এবং Rails সহ একটি সম্পূর্ণ-স্ট্যাক অ্যাপ্লিকেশন তৈরি করা

স্কেলেবিলিটির কথা মাথায় রেখে ফুল-স্ট্যাক অ্যাপ্লিকেশন তৈরি করা ভীতিজনক হতে পারে, বিশেষ করে যখন Vue এবং Vuex-এর সর্বশেষ সংস্করণ দিয়ে তৈরি করা হয়, যার সম্পূর্ণ টাইপস্ক্রিপ্ট সমর্থন রয়েছে। এই নিবন্ধটি তার পাঠকদেরকে Vuex 4.0 এর সাথে রাষ্ট্রীয় ব্যবস্থাপনা থেকে পরিমাপযোগ্য ফুল-স্ট্যাক অ্যাপ্লিকেশন তৈরি করার বিষয়ে যা জানা দরকার তা শিখিয়ে দেবে একটি CRUD অ্যাপ্লিকেশন অন্বেষণ করে যা অস্বাস্থ্যকর গবাদি পশুর চিকিৎসার ব্যবস্থাপত্র পরিচালনা করে API অনুরোধ এবং ডাটাবেস মিথস্ক্রিয়া পরিচালনা করতে। ব্যাকএন্ডটি রেলের সাথে তৈরি করা হবে, ফ্রন্টএন্ড দ্বারা ইন্টিগ্রেশনের জন্য মৌলিক CRUD API গুলিকে প্রকাশ করবে৷

বেশিরভাগ কোম্পানি API-ভিত্তিক ডেভেলপমেন্ট আর্কিটেকচার গ্রহণ করেছে কারণ এটি ফ্রন্টএন্ড ডেভেলপমেন্ট টিমকে ডেভেলপমেন্টের জন্য একটি উপযুক্ত ফ্রন্টএন্ড টুল বেছে নিতে আরও নমনীয়তা দেয়। যদিও এটি সর্বোত্তম বিকল্প নাও হতে পারে, এটি একটি নির্ভরযোগ্য বিকল্প, এবং অনেক কোম্পানি এই উন্নয়ন স্থাপত্যকে গ্রহণ করেছে কারণ এটি দলে আরও নমনীয়তা যোগ করে৷

পূর্বশর্ত

আমরা শুরু করার আগে, নিশ্চিত করুন যে আপনার কাছে এই টিউটোরিয়ালটি বজায় রাখার জন্য নিম্নলিখিতগুলি আছে:

  • রেল V6.x
  • Node.js V10.x
  • রুবি অন রেল সম্পর্কে পূর্বের কাজের জ্ঞান
  • টাইপস্ক্রিপ্টের পূর্বের কাজের জ্ঞান
  • Vue.js এর পূর্বের কাজের জ্ঞান

আমরা কি নির্মাণ করব

Vue, Vuex এবং Rails সহ একটি সম্পূর্ণ-স্ট্যাক অ্যাপ্লিকেশন তৈরি করা

এই টিউটোরিয়ালে, আমরা একটি পূর্ণ-স্ট্যাক CRUD অ্যাপ্লিকেশন তৈরি করব যা অস্বাস্থ্যকর গবাদি পশুর চিকিৎসার ব্যবস্থাপত্র পরিচালনা করে। ব্যবহারকারীরা গবাদি পশুর জন্য প্রেসক্রিপশন তৈরি করতে, আপডেট করতে এবং মুছে ফেলতে সক্ষম হবেন। CRUD API গুলি Rails ব্যবহার করে তৈরি করা হবে, CRUD APIগুলিকে ফ্রন্টএন্ড দ্বারা একীকরণের জন্য উন্মুক্ত করে, যা Vue 3 দিয়ে নির্মিত হবে৷ এই স্ট্যাকগুলির প্রতিটি স্বাধীন অ্যাপ্লিকেশন হিসাবে বিভিন্ন পোর্টে চলবে৷

ফুল-স্ট্যাক অ্যাপের বেসিক আর্কিটেকচার

আমাদের ফুল-স্ট্যাক অ্যাপ্লিকেশনটি ক্লায়েন্ট এবং সার্ভার উভয় অ্যাপ্লিকেশনের সমন্বয়ে গঠিত যা স্বাধীনভাবে চলছে, ক্লায়েন্ট অ্যাপ্লিকেশনের প্রতিটি উপাদান অ্যাপ্লিকেশন অবস্থার সঠিক ব্যবস্থাপনার জন্য Vuex এর মাধ্যমে সার্ভার অ্যাপ্লিকেশন দ্বারা জারি করা CRUD API-এর সাথে ইন্টারঅ্যাক্ট করে। ব্যাকএন্ড অ্যাপ্লিকেশনটি একটি Sqlite 3 ডাটাবেসে সমস্ত প্রেসক্রিপশন ডেটা সঞ্চয় করে যখন ফ্রন্টএন্ড অ্যাপ্লিকেশনে CRUD APIগুলি প্রকাশ করে৷

ব্যাকএন্ড পরিষেবা সেটআপ

আপনার পছন্দের একটি ফোল্ডারে, নিম্নলিখিত কমান্ডটি চালিয়ে একটি Rails অ্যাপ তৈরি করুন:

rails new vet_clinic_api --api

এটি রেলকে একটি API হিসাবে এই প্রকল্পটি তৈরি করতে বলবে, যার ফলে সমস্ত ফ্রন্টএন্ড নির্ভরতা (ফাইলগুলি দেখুন) মুছে ফেলা হবে।

ডাটাবেস কনফিগারেশন

আমরা Sqlite 3 ব্যবহার করব, যা রেল অ্যাপ্লিকেশনের জন্য ডিফল্ট ডাটাবেস।

rails g scaffold prescriptions vet_prescription:text prescribed_by:text disease:text livestock:text completed:boolean

উপরের কমান্ডটি চালানোর মাধ্যমে, রেলগুলি আমাদের মাইগ্রেশন, পরীক্ষা, মডেল, কন্ট্রোলার, রুটের জন্য একটি প্রাথমিক কাঠামো তৈরি করবে:

rails db:migrate

এই কমান্ডটি ডাটাবেসে আমাদের টেবিল যোগ করবে।

ডাটাবেস সিডিং

আসুন কিছু প্রেসক্রিপশন ডেটা দিয়ে আমাদের ডাটাবেস তৈরি করি৷ নিচের কোড স্নিপেটটি db/migrate/seed.rb-এ যোগ করুন

//db/migrate/seed.rb

Prescription.destroy_all
Prescription.create!([{
    vet_prescription:"Achyranthes aspera",
    prescribed_by:"Dr Chucks",
    disease:"Rabbies",
    livestock:"goat",
    completed:false
},
{
    vet_prescription:"Achyranthes aspera",
    prescribed_by:"Dr Rex",
    disease:"Rabbies",
    livestock:"Dog",
    completed:false
},
{
    vet_prescription:"ethnovet",
    prescribed_by:"Dr Chucks",
    disease:"Pox",
    livestock:"Sheep",
    completed:false
}])
p "Created #{Prescription.count} prescriptions"

এই ফাইলটি ডাটাবেস সিডিংয়ের জন্য প্রাথমিক ডেটা সংরক্ষণ করবে যাতে অ্যাপটি শুরু হলে, আমাদের কাছে কিছু বিদ্যমান প্রেসক্রিপশন ডেটা থাকবে।

db/migrate/seed.rb-এ কোডটি কার্যকর করতে নিম্নলিখিত কমান্ডটি চালান , যা কিছু পূর্বনির্ধারিত প্রেসক্রিপশন ডেটা সহ ডাটাবেস বীজ করে:

rails db:seed

এই কয়েকটি কমান্ড দিয়ে, আমরা রেলের সাথে একটি কার্যকরী CRUD API তৈরি করেছি। এটা কত সহজ ছিল? (হাসি)

CORS কনফিগারেশন

যেহেতু আমরা আমাদের CRUD APIগুলিকে ফ্রন্টএন্ডে প্রকাশ করব, এবং ফ্রন্টএন্ড এবং ব্যাকএন্ড সার্ভার উভয়ই একটি ভিন্ন পোর্টে চলবে, তাই ফ্রন্টএন্ড এবং এর মধ্যে ডেটা ভাগ করে নেওয়ার অ্যাক্সেস দেওয়ার জন্য আমাদের রেল ব্যাকএন্ডে একটি CORS কনফিগারেশন সেট আপ করতে হবে ব্যাকএন্ড।

Gemfile সনাক্ত করুন প্রজেক্ট রুটে এবং কোডের নিম্নলিখিত লাইনটি আনকমেন্ট করুন:

# gem 'rack-cors'

config/environments/initializers/cors.rb-এ নিম্নলিখিত কোড যোগ করুন :

//config/environments/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'
    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

উপরের স্নিপেটটি Rails CRUD API-কে যেকোনো PORT-এ চলমান ফ্রন্টএন্ড অ্যাপ থেকে অ্যাক্সেসযোগ্য করার অনুমতি দেয়।

Rails সার্ভার শুরু করতে নিম্নলিখিত কমান্ডটি চালান:

rails s

localhost:3000/prescriptions-এ নেভিগেট করুন সমস্ত প্রেসক্রিপশনের জন্য একটি JSON প্রতিক্রিয়া পেতে।

আপনি যদি ক্লায়েন্টদের সাথে কাজ করেন যারা তাদের প্রকল্পের কর্মপ্রবাহ ঘন ঘন পরিবর্তন করে তাহলে রেল ব্যবহার করার কথা বিবেচনা করুন। রেলের সাথে, কয়েকটি কমান্ড এবং কোডের লাইন সহ বৈশিষ্ট্যগুলি বাস্তবায়ন করা সহজ। যদিও এটা আমার ব্যক্তিগত মতামত।

প্রবর্তন করা হচ্ছে Vue

Vue হল একটি প্রগতিশীল কাঠামো ইউজার ইন্টারফেস তৈরির জন্য। Vue ওয়েব অ্যাপ্লিকেশনের জন্য উল্লেখযোগ্য পারফরম্যান্স অপ্টিমাইজেশান প্রদান করতে ভার্চুয়াল DOM, রেন্ডার ফাংশন এবং সার্ভার-সাইড রেন্ডারিং ক্ষমতার মতো ধারণাগুলি প্রবর্তন করে৷

Vue 3 অনেক নতুন বৈশিষ্ট্য এবং বিকাশকারীদের জন্য পরিবর্তন নিয়ে আসে। এই বৈশিষ্ট্যগুলি ফ্রেমওয়ার্কের সামগ্রিক স্থিতিশীলতা, সেইসাথে এর গতি এবং রক্ষণাবেক্ষণযোগ্যতা উন্নত করার জন্য ডিজাইন করা হয়েছে৷

আমরা কম্পোজিশন API ব্যবহার করব, Vue 3-এর সবচেয়ে প্রত্যাশিত বৈশিষ্ট্যগুলির মধ্যে একটি। এটি Vue উপাদানগুলি তৈরি করার একটি নতুন উপায়, কোড লেখার জন্য আরও সংগঠিত এবং দক্ষ পদ্ধতির সাথে এবং সম্পূর্ণ টাইপস্ক্রিপ্ট টাইপ-চেকিং সমর্থন।

ভিউএক্স প্রবর্তন

Vuex হল Vue দল দ্বারা তৈরি একটি রাষ্ট্রীয় ব্যবস্থাপনা লাইব্রেরি, এবং এটি Redux-এর মতো একই ফ্লাক্স আর্কিটেকচারের উপর ভিত্তি করে তৈরি। এটি বিশেষভাবে Vue-এর জন্য ডিজাইন করা হয়েছে এবং আপনার দোকানের আরও ভাল সংগঠনের অনুমতি দেয়। Vuex গুরুত্বপূর্ণ হয়ে উঠবে যদি আপনার Vue অ্যাপ্লিকেশন অবস্থা বৃদ্ধির সাথে সাথে আরও জটিল হয়। Vuex-এর সর্বশেষ স্থিতিশীল রিলিজ, v4.0.0, Vue 3-এ প্রবর্তিত কম্পোজিশন API সমর্থন করে, পাশাপাশি TypeScript-এর জন্য আরও শক্তিশালী অনুমান।

ফ্রন্টএন্ড অ্যাপ্লিকেশন সেট আপ করা হচ্ছে

ফ্রন্টএন্ড Vue 3 এবং typeScript এর সাথে সেটআপ করা হবে, যখন Vuex ব্যবহার করা হবে অ্যাপ্লিকেশন স্টেট ম্যানেজমেন্টের জন্য৷

টাইপস্ক্রিপ্ট সমর্থন সহ একটি Vue 3 অ্যাপ তৈরি করতে Vue-CLI টুল ব্যবহার করে শুরু করা যাক।

নিম্নোক্ত কমান্ডের মাধ্যমে বিশ্বব্যাপী Vue-CLI টুল ইনস্টল করুন:

npm install --global @vue/cli

নিচের কমান্ডের সাহায্যে টাইপস্ক্রিপ্ট এবং Vuex সমর্থন সহ একটি নতুন Vue 3 অ্যাপ তৈরি করুন:

vue create vet_clinic_frontend

ম্যানুয়ালি নির্বাচন করুন বৈশিষ্ট্য বিকল্পটি চয়ন করুন এবং নিম্নলিখিত বিকল্পগুলি নির্বাচন করতে স্পেস কী টিপুন:

  • ভিউ সংস্করণ চয়ন করুন
  • বাবেল
  • টাইপস্ক্রিপ্ট
  • লিন্টার / ফরম্যাটার

এরপরে, প্রকল্পের সংস্করণ হিসেবে Vue 3.x(প্রিভিউ) বেছে নিন।

  • শ্রেণী-শৈলী উপাদান সিনট্যাক্স ব্যবহার করতে হ্যাঁ লিখুন।
  • টাইপস্ক্রিপ্টের পাশাপাশি ব্যাবেল ব্যবহার করতে হ্যাঁ লিখুন।
  • আপনার পছন্দের যেকোন লিন্টার নির্বাচন করুন।

একবার Vue 3 অ্যাপটি সফলভাবে তৈরি হয়ে গেলে, আমাদের কাছে Vuex (V4.x) এবং সম্পূর্ণ টাইপস্ক্রিপ্ট সমর্থন সহ একটি Vue 3 প্রকল্প সেটআপ থাকবে৷

আমরা টাইপস্ক্রিপ্ট ব্যবহার করে অ্যাপ্লিকেশনটিতে টাইপ নিরাপত্তা যোগ করব। ডেভেলপমেন্ট সার্ভার শুরু করতে, আপনার টার্মিনালে নীচের কমান্ডটি চালান এবং https://localhost:8080-এ যান ব্রাউজারে আপনার প্রকল্পের পূর্বরূপ দেখতে।

আমরা আমাদের অ্যাপ্লিকেশন স্টাইল করার জন্য Bulma CSS ফ্রেমওয়ার্ক ব্যবহার করব। বুলমা সিএসএস ইনস্টল করতে নিম্নলিখিত কমান্ডটি চালান:

npm install bulma

Bulma CSS আমদানি করতে, App.vue-এ নিম্নলিখিত কোড যোগ করুন :

//App.vue
<style lang="scss">
@import "~bulma/css/bulma.css";
</style>

অ্যাপ্লিকেশন স্টোর সেট আপ করা হচ্ছে

অ্যাপ্লিকেশন স্টোরটি Vuex-এর সাথে সেটআপ করা হবে৷ স্টোরে পরিবর্তন করতে, উপাদান থেকে অ্যাকশন পাঠানো হবে, যা মিউটেশনগুলিকে ট্রিগার করে, যার ফলে স্টোর আপডেট হয়৷

অ্যাপ্লিকেশন স্টোর সেট আপ করতে নিম্নলিখিত পদক্ষেপগুলি নিন:

  1. স্টেট অবজেক্ট তৈরি করুন।
  2. আমাদের অ্যাপ্লিকেশনে যে মিউটেশনগুলি ঘটবে তা সেট আপ করুন৷
  3. এই পরবর্তী মিউটেশনগুলির জন্য প্রতিশ্রুতিবদ্ধ কাজগুলি তৈরি করুন৷
  4. সরাসরি রাজ্য ডেটা গণনা করার জন্য উপাদানগুলির জন্য গেটার তৈরি করুন৷

রাজ্য

একটি রাষ্ট্র হল একটি স্টোর অবজেক্ট যা অ্যাপ্লিকেশন-স্তরের ডেটা ধারণ করে যা সমস্ত উপাদান দ্বারা অ্যাক্সেস করা প্রয়োজন৷

একটি state.ts তৈরি করুন নিম্নলিখিত কোড স্নিপেট সহ স্টোর ডিরেক্টরিতে ফাইল করুন:

//src/store/state.ts
export type Prescription = {
  id: number;
  vet_prescription: string;
  prescribed_by: string;
  disease: string;
  livestock: string;
  completed: boolean;
  editing: boolean;
};
export type Data = {
  vet_prescription: string;
  prescribed_by: string;
  disease: string;
  livestock: string;
};
export type State = {
  loading: boolean;
  prescriptions: Prescription[];
  data: Data | null;
  showCreateModal: boolean;
  showEditModal: boolean;
  showPrescriptionModal: boolean;
  editModalPrescriptionId: number | undefined;
  showPrescriptionId: number | undefined;
};
export const state: State = {
  loading: false,
  prescriptions: [],
  data: null,
  showCreateModal: false,
  showEditModal: false,
  showPrescriptionModal: false,
  editModalPrescriptionId: undefined,
  showPrescriptionId: undefined,
};

এখানে, আমরা Prescription-এ কিছু ধরনের নিরাপত্তা যোগ করি এবং Data . আমরা প্রকারগুলিও রপ্তানি করি কারণ সেগুলি গেটার, মিউটেশন এবং ক্রিয়াগুলির সংজ্ঞায় ব্যবহৃত হবে। অবশেষে, আমরা স্টেট টাইপকে স্টেটে কাস্ট করি।

মিউটেশন

মিউটেশন হল এমন পদ্ধতি যা, যখন ট্রিগার হয়, তখন স্টোরটি পরিবর্তন করে। তারা প্রথম আর্গুমেন্ট হিসেবে স্টেট গ্রহণ করে এবং দ্বিতীয়টি পেলোড হিসেবে, অবশেষে পেলোড দিয়ে অ্যাপ্লিকেশান স্টেট পরিবর্তন করে। মিউটেশন তৈরি করতে, Vuex ডক্স মিউটেশন প্রকারের জন্য ধ্রুবক ব্যবহার করার পরামর্শ দেয়।

একটি mutations.ts তৈরি করুন নিম্নলিখিত কোড স্নিপেট সহ স্টোর ডিরেক্টরিতে ফাইল করুন:

//src/store/mutations.ts
import { MutationTree } from "vuex";
import { State, Prescription, Data } from "./state";

export enum MutationType {
  CreatePrescription = "CREATE_PRESCRIPTION",
  SetPrescriptions = "SET_PRESCRIPTIONS",
  CompletePrescription = "COMPLETE_PRESCRIPTION",
  RemovePrescription = "REMOVE_PRESCRIPTION",
  EditPrescription = "EDIT_PRESCRIPTION",
  UpdatePrescription = `UPDATE_PRESCRIPTION`,

  SetLoading = "SET_LOADING",
  SetCreateModal = "SET_CREATE_MODAL",
  SetEditModal = "SET_EDIT_MODAL",
  SetPrescriptionModal = "SET_PRESCRIPTION_MODAL",
}

উপরের স্নিপেটটি আমাদের অ্যাপে মিউটেশনের সম্ভাব্য সব নাম ধরে রাখতে enum চিহ্ন ব্যবহার করে।

এর পরে, আমরা প্রতিটি মিউটেশন টাইপের জন্য একটি চুক্তি (টাইপ) ঘোষণা করব, নিম্নরূপ:

//src/store/mutation.ts
export type Mutations = {
  [MutationType.CreatePrescription](state: State, prescription: Data): void;

  [MutationType.SetPrescriptions](state: State, prescription: Prescription[]): void;

  [MutationType.CompletePrescription](state: State, prescription: Partial<Prescription> & { id: number }): void;

  [MutationType.RemovePrescription](state: State, prescription: Partial<Prescription> & { id: number }): void;

  [MutationType.EditPrescription](state: State, prescription: Partial<Prescription> & { id: number }): void;

  [MutationType.UpdatePrescription](state: State, prescription: Partial<Prescription> & { id: number }): void;

  [MutationType.SetLoading](state: State, value: boolean): void;

  [MutationType.SetCreateModal](state: State, value: boolean): void;

  [MutationType.SetEditModal](state: State, value: { showModal: boolean; prescriptionId: number | undefined }): void;

  [MutationType.SetPrescriptionModal](state: State, value: { showModal: boolean; prescriptionId: number | undefined }): void;
};

তারপর, আমরা প্রতিটি MutationType-এর জন্য ঘোষিত চুক্তিগুলি বাস্তবায়ন করব , নিম্নরূপ:

//src/store/mutation.ts
export const mutations: MutationTree<State> & Mutations = {
  [MutationType.CreatePrescription](state, prescription) {
    state.data == prescription;
  },
  [MutationType.SetPrescriptions](state, prescriptions) {
    state.prescriptions = prescriptions;
  },
  [MutationType.CompletePrescription](state, newPrescription) {
    const prescription = state.prescriptions.findIndex((prescription) => prescription.id === newPrescription.id);
    if (prescription === -1) return;
    state.prescriptions[prescription] = { ...state.prescriptions[prescription], ...newPrescription };
  },
  [MutationType.RemovePrescription](state, Prescription) {
    const prescription = state.prescriptions.findIndex((prescription) => prescription.id === Prescription.id);
    if (prescription === -1) return;
    //If prescription exist in the state, remove it
    state.prescriptions.splice(prescription, 1);
  },
  [MutationType.EditPrescription](state, Prescription) {
    const prescription = state.prescriptions.findIndex((prescription) => prescription.id === Prescription.id);
    if (prescription === -1) return;
    //If prescription exist in the state, toggle the editing property
    state.prescriptions[prescription] = { ...state.prescriptions[prescription], editing: !state.prescriptions[prescription].editing };
    console.log("prescription", state.prescriptions[prescription]);
  },
  [MutationType.UpdatePrescription](state, Prescription) {
    state.prescriptions = state.prescriptions.map((prescription) => {
      if (prescription.id === Prescription.id) {
        return { ...prescription, ...Prescription };
      }
      return prescription;
    });
  },

  [MutationType.SetLoading](state, value) {
    state.loading = value;
  },
  [MutationType.SetCreateModal](state, value) {
    state.showCreateModal = value;
  },
  [MutationType.SetEditModal](state, value) {
    state.showEditModal = value.showModal;
    state.editModalPrescriptionId = value.prescriptionId;
  },
  [MutationType.SetPrescriptionModal](state, { showModal, prescriptionId }) {
    state.showPrescriptionModal = showModal;
    state.showPrescriptionId = prescriptionId;
  },
};

MutationTree Vuex প্যাকেজের সাথে পাঠানো একটি সাধারণ প্রকার। আমরা উপরের স্নিপেটে এটি ব্যবহার করেছি এক ধরনের মিউটেশন ট্রি ঘোষণা করতে। মিউটেশন ট্রি এবং মিউটেশন নিশ্চিত করে যে চুক্তিটি সঠিকভাবে বাস্তবায়িত হয়েছে; অন্যথায়, টাইপস্ক্রিপ্ট একটি ত্রুটি ট্রিগার করবে।

ক্রিয়া

ক্রিয়াগুলি এমন পদ্ধতি যা মিউটেশনকে ট্রিগার করে। অ্যাসিঙ্ক্রোনাস কাজগুলি পরিচালনা করার সময়, যেমন একটি API-তে অনুরোধ করা, API প্রতিক্রিয়ার সাথে সংশ্লিষ্ট মিউটেশনগুলিকে পেলোড হিসাবে কল করার আগে অ্যাকশনগুলি ব্যবহার করা হয়। আমরা আমাদের কর্মগুলি তৈরি করার সাথে সাথে এই দৃশ্যের জন্য একটি স্পষ্ট বাস্তবায়ন পাব৷

অ্যাকশন তৈরি করার আগে, আমরা Rails সার্ভারে আমাদের সমস্ত Http অনুরোধ পরিচালনা করতে Axios ইনস্টল করব, নিম্নরূপ:

npm install axios --save

একটি actions.ts তৈরি করুন নিম্নলিখিত কোড স্নিপেট সহ স্টোর ডিরেক্টরিতে ফাইল করুন:

//src/store/actions.ts
import { ActionContext, ActionTree } from "vuex";
import { Mutations, MutationType } from "./mutations";
import { State, Prescription, Data } from "./state";
import axios from "axios";
const apiUrl = "https://localhost:3000/prescriptions";
export enum ActionTypes {
  GetPrescriptions = "GET_PRESCRIPTIONS",
  SetCreateModal = "SET_CREATE_MODAL",
  SetEditModal = "SET_EDIT_MODAL",
  RemovePrescription = "REMOVE_PRESCRIPTION",
  CreatePrescription = "CREATE_PRESCRIPTION",
  UpdatePrescription = "UPDATE_PRESCRIPTION",
}

একইভাবে, উপরের স্নিপেটটি আমাদের অ্যাপে অ্যাকশনের সম্ভাব্য সব নাম ধরে রাখতে enum চিহ্ন ব্যবহার করে।

এর পরে, আমরা প্রতিটি অ্যাকশন টাইপের জন্য একটি চুক্তি (টাইপ) ঘোষণা করব, নিম্নরূপ:

//src/store/actions.ts
type ActionAugments = Omit<ActionContext<State, State>, "commit"> & {
  commit<K extends keyof Mutations>(key: K, payload: Parameters<Mutations[K]>[1]): ReturnType<Mutations[K]>;
};

export type Actions = {
  [ActionTypes.GetPrescriptions](context: ActionAugments): void;
  [ActionTypes.SetCreateModal](context: ActionAugments): void;
  [ActionTypes.SetEditModal](context: ActionAugments): void;
  [ActionTypes.RemovePrescription](context: ActionAugments, Prescription: { id: number }): void;
  [ActionTypes.CreatePrescription](context: ActionAugments, data: Data): void;
  [ActionTypes.UpdatePrescription](context: ActionAugments, prescription: Prescription): void;
};

ActionAugments টাইপ সমস্ত কমিটকে শুধুমাত্র তাদের ঘোষিত মিউটেশনের জন্য এবং পেলোডের ধরন পরীক্ষা করার জন্য সীমাবদ্ধ করে।

পরবর্তী, আমরা প্রতিটি অ্যাকশন টাইপের জন্য ঘোষিত চুক্তি (প্রকার) বাস্তবায়ন করব। নিচের কোডটি action.ts ফাইলে যোগ করুন:

//src/store/actions.ts
export const actions: ActionTree<State, State> & Actions = {
  async [ActionTypes.GetPrescriptions]({ commit }) {
    commit(MutationType.SetLoading, true);

    const response = await axios.get(apiUrl);

    commit(MutationType.SetLoading, false);
    commit(MutationType.SetPrescriptions, response.data);
  },

  async [ActionTypes.SetCreateModal]({ commit }) {
    commit(MutationType.SetCreateModal, true);
  },

  async [ActionTypes.SetEditModal]({ commit }) {
    commit(MutationType.SetEditModal, { showModal: true, prescriptionId: 1 });
  },

  //Optimistic update
  async [ActionTypes.RemovePrescription]({ commit }, Prescription) {
    if (Prescription != undefined) {
      commit(MutationType.RemovePrescription, Prescription);
    }

    const response = await axios.delete(`${apiUrl}/${Prescription.id}`);
  },

  async [ActionTypes.CreatePrescription]({ commit, dispatch }, Prescription) {
    const response = await axios.post(apiUrl, Prescription);
    dispatch(ActionTypes.GetPrescriptions);
  },

  async [ActionTypes.UpdatePrescription]({ commit, dispatch }, Prescription) {
    if (Prescription != undefined) {
      commit(MutationType.UpdatePrescription, Prescription);
      const response = await axios.patch(`${apiUrl}/${Prescription.id}`, Prescription);
      dispatch(ActionTypes.GetPrescriptions);
    }
  },
};

এখানে, আমরা একটি অ্যাকশন ভেরিয়েবল তৈরি করেছি যা সমস্ত বাস্তবায়িত অ্যাকশন সংরক্ষণ করে। একইভাবে, ActionTree<State> & Actions নিশ্চিত করে যে চুক্তি (type Actions ) সঠিকভাবে প্রয়োগ করা হয়; অন্যথায়, টাইপস্ক্রিপ্ট একটি ত্রুটি ট্রিগার করবে।

আমরা GetPrescriptions-এ Rails API এন্ডপয়েন্টে আমাদের অ্যাসিঙ্ক্রোনাস কল সেট আপ করি অ্যাকশন এবং SetPrescriptions ট্রিগার করেছে পেলোড হিসাবে প্রতিক্রিয়া ডেটা সহ মিউটেশন প্রকার। এছাড়াও আমরা SetCreateModal সেট আপ করি , SetEditModal , CreatePrescription , UpdatePrescription, এবং RemovePrescription কর্ম।

Geters

Getters হল এমন পদ্ধতি যা স্টেটকে তার প্রথম প্যারামিটার হিসেবে গ্রহণ করে এবং স্টোর স্টেট থেকে গণনাকৃত তথ্য ফেরত দেয়।

একটি getters.ts তৈরি করুন নিম্নলিখিত কোড স্নিপেট সহ স্টোর ডিরেক্টরিতে ফাইল করুন:

//src/store/getters.ts
import { GetterTree } from "vuex";
import { State, Prescription } from "./state";
export type Getters = {
  completedPrescriptionCount(state: State): number;
  totalPrescriptionCount(state: State): number;
  getPrescriptionById(state: State): (id: number) => Prescription | undefined;
};
export const getters: GetterTree<State, State> & Getters = {
  completedPrescriptionCount(state) {
    return state.prescriptions.filter((prescription) => prescription.completed).length;
  },
  totalPrescriptionCount(state) {
    return state.prescriptions.length;
  },
  getPrescriptionById: (state) => (id: number) => {
    return state.prescriptions.find((prescription) => prescription.id === id);
  },
};

উপরের কোড স্নিপেট নিম্নলিখিত গেটারকে সংজ্ঞায়িত করে:

  • completedPrescriptionCount – একটি ফাংশন যা আমাদের রাজ্যে সম্পূর্ণ প্রেসক্রিপশনের মোট সংখ্যা পায়।
  • totalPrescriptionCount – একটি ফাংশন যা আমাদের রাজ্যে প্রেসক্রিপশনের মোট সংখ্যা পায়।
  • getPrescriptionById – একটি ফাংশন যা তার আইডি দ্বারা একটি প্রেসক্রিপশন পায়৷

আমরা Getters-এ কিছু ধরনের নিরাপত্তা যোগ করেছি।

স্টোর

আসুন আমাদের state ওয়্যার করি , mutations , actions , এবং getters বিশ্বব্যাপী Vuex দোকানে। আমরা store/index.ts আপডেট করব , নিম্নরূপ:

//src/store/index.ts
import { createStore, Store as VuexStore, CommitOptions, DispatchOptions, createLogger } from "vuex";
import { State, state } from "./state";
import { Mutations, mutations } from "./mutations";
import { Actions, actions } from "./actions";
import { Getters, getters } from "./getters";
export const store = createStore<State>({
  plugins: process.env.NODE_ENV === "development" ? [createLogger()] : [],
  state,
  mutations,
  actions,
  getters,
});
export function useStore() {
  return store as Store;
}
export type Store = Omit<VuexStore<State>, "getters" | "commit" | "dispatch"> & {
  commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(key: K, payload: P, options?: CommitOptions): ReturnType<Mutations[K]>;
} & {
  dispatch<K extends keyof Actions>(key: K, payload?: Parameters<Actions[K]>[1], options?: DispatchOptions): ReturnType<Actions[K]>;
} & {
  getters: {
    [K in keyof Getters]: ReturnType<Getters[K]>;
  };
};

state , mutations , actions , এবং getters createStore-এ সেগুলি ধারণকারী একটি বস্তু পাস করে একটি স্টোর তৈরি করতে হবে পদ্ধতি বিকাশের সময়, createLogger প্লাগইন রাজ্য (আগের অবস্থা এবং পরবর্তী অবস্থা) এবং কনসোলে মিউটেশনগুলি লগ করে৷ আমাদের অ্যাপ্লিকেশনের সমস্ত উপাদানগুলিতে স্টোর অ্যাক্সেসযোগ্য করার জন্য; আমাদের এটি সম্পূর্ণ অ্যাপ্লিকেশনে ইনজেকশন করতে হবে। সৌভাগ্যবশত, Vue-CLI টুল ইতিমধ্যেই সমগ্র স্টোরটি আমদানি করেছে এবং এটিকে অ্যাপ্লিকেশনের Vue উদাহরণের মধ্যে পাস করেছে৷

ভিউএক্স স্টোরকে কম্পোনেন্টে একীভূত করা

এই টিউটোরিয়ালে, আমাদের ফ্রন্টএন্ড অ্যাপ্লিকেশনের সমস্ত উপাদান তৈরি করতে Vue 3 রচনা API ব্যবহার করা হবে৷

অ্যাপ উপাদান

আমাদের ফ্রন্টএন্ড এটি চালু হওয়ার সাথে সাথে প্রেসক্রিপশন ডেটার একটি তালিকা রেন্ডার করা উচিত। আমরা GetPrescription পাঠাব কম্পোনেন্টের mounted()-এর মধ্যে কাজ জীবনচক্র হুক। একটি উপাদানের মধ্যে দোকান অ্যাক্সেস করতে, useStore হুক, যা আমাদের দোকানে ফেরত দেয়, তা কার্যকর করা হবে।

//src/App.vue
<script lang="ts">
import { computed, defineComponent, onMounted } from "vue";
import PrescriptionList from "./components/PrescriptionList.vue";
import { useStore } from "./store";
import { ActionTypes } from "./store/actions";
export default defineComponent({
  components: { PrescriptionList },
  setup() {
    const store = useStore();
    const loading = computed(() => store.state.loading);
    onMounted(() => store.dispatch(ActionTypes.GetPrescriptions));
    const completedCount = computed(() => store.getters.completedPrescriptionCount);
    const totalCount = computed(() => store.getters.totalPrescriptionCount);
    return { loading, completedCount, totalCount };
  },
});
</script>
<template>
  <nav class="navbar" role="navigation" aria-label="main navigation">
    <div class="navbar-brand">
      <a class="navbar-item" href="https://bulma.io">
        <img src="https://bulma.io/images/bulma-logo.png" width="112" height="28" />
      </a>
    </div>
    <div id="navbarBasicExample" class="navbar-menu">
      <div class="navbar-start">
        <a class="navbar-item"> Home </a>
        <a class="navbar-item"> About </a>
      </div>
    </div>
  </nav>
  <div class="container mx-auto mt-4">
    <h1 class="is-size-3 has-text-centered p-2 has-text-weight-bold is-success">Vet clinic Frontend</h1>
    <h3 class="has-text-centered p-2">Manage records of treated livestock in your farm</h3>
    <div v-if="loading">
      <h3 class="has-text-centered mt-4">Loading...</h3>
    </div>
    <div v-else>
      <p class="has-text-centered mt-2">{{ completedCount }} of {{ totalCount }} treated.</p>
      <PrescriptionList />
    </div>
  </div>
</template>
<style>
@import "~bulma/css/bulma.css";
</style>

এখানে, আমরা তিনটি গণিত বৈশিষ্ট্য তৈরি করেছি:

  • completedCount , যা completedPrescriptionCount কল করে সম্পূর্ণ চিকিত্সার মোট সংখ্যা পুনরুদ্ধার করার জন্য গেটার পদ্ধতি।
  • totalCount , যা totalPrescriptionCount কল করে প্রেসক্রিপশনের মোট সংখ্যা পুনরুদ্ধার করার জন্য গেটার পদ্ধতি।
  • loading , যা রাষ্ট্রের লোডিং সম্পত্তি পায়।

Vue 3 কম্পোজিশন API এর সাথে, টেমপ্লেটের জন্য প্রয়োজনীয় পদ্ধতি এবং বৈশিষ্ট্যগুলিকে টেমপ্লেটে অ্যাক্সেসযোগ্য হওয়ার জন্য ফেরত দিতে হবে। লক্ষ্য করুন কিভাবে আমরা loading, completedCount, and totalCount ফেরত দিয়েছি .

প্রেসক্রিপশনলিস্ট উপাদান

এই উপাদানটি ব্যাকএন্ড থেকে প্রেসক্রিপশনের তালিকা পুনরুদ্ধার করার জন্য এবং এটির শিশু উপাদানে প্রেসক্রিপশন ডেটা পাঠানোর জন্য দায়ী থাকবে৷

PrescriptionList.vue তৈরি করুন নিম্নলিখিত কোড সহ উপাদান ফোল্ডারের ভিতরে:

//src/components/PrescriptionList.vue
<template>
  <table class="table is-hoverable is-striped">
    <thead>
      <tr>
        <th><abbr title="Position">Prescription Id</abbr></th>
        <th>Treated</th>
        <th>Prescription</th>
        <th><abbr title="Won">Prescribed By</abbr></th>
        <th><abbr title="Drawn">Disease</abbr></th>
        <th><abbr title="Drawn">Livestock</abbr></th>
        <th><abbr title="Lost">Actions</abbr></th>
      </tr>
    </thead>
    <tbody v-if="prescriptions">
      <tr v-for="prescription in prescriptions" :key="prescription.id">
        <PrescriptionListItem v-bind="prescription" />
      </tr>
    </tbody>
    <tfoot>
      <CreateModal v-show="showCreateModal"></CreateModal>
      <button class="button  is-success" @click="setModal">Create Prescription</button>
    </tfoot>
  </table>
  <EditModal v-if="showEditModal" :id="editModalPrescriptionId"></EditModal>
  <Prescription v-if="showPrescriptionModal" :id="showPrescriptionId"></Prescription>
</template>
<script>
import CreateModal from "./CreateModal";
import EditModal from "./EditModal";
import Prescription from "./Prescription";
import PrescriptionListItem from "./PrescriptionListItem";
import { defineComponent, computed } from "vue";
import { useStore } from "@/store";
import { MutationType } from "@/store/mutations";
export default defineComponent({
  name: "Table",
  components: {
    CreateModal,
    PrescriptionListItem,
    Prescription,
    EditModal,
  },
  setup() {
    const store = useStore();
    const setModal = () => {
      store.commit(MutationType.SetCreateModal, true);
    };
    const showCreateModal = computed(() => store.state.showCreateModal);
    const showEditModal = computed(() => store.state.showEditModal);
    const editModalPrescriptionId = computed(() => store.state.editModalPrescriptionId);
    const showPrescriptionModal = computed(() => store.state.showPrescriptionModal);
    const showPrescriptionId = computed(() => store.state.showPrescriptionId);
    const prescriptions = computed(() => store.state.prescriptions);
    return { showCreateModal, setModal, prescriptions, showEditModal, showPrescriptionModal, editModalPrescriptionId, showPrescriptionId };
  },
});
</script>
<style scoped>
table {
  width: 100%;
}
.fa {
  font-size: 1.2rem;
  margin-left: 15px;
}
.fa:hover {
  font-size: 1.4rem;
}
</style>

setModal মেথড সেই মিউটেশনকে আহ্বান করে যা showCreateModal সেট করে রাজ্যে সত্য, যার ফলে প্রেসক্রিপশন তৈরির জন্য মডেল চালু হচ্ছে।

আমরা নিম্নলিখিত গণনা করা বৈশিষ্ট্যগুলি তৈরি করেছি:

  • showCreateModal , যা showCreateModal পায় রাষ্ট্রের সম্পত্তি।
  • showEditModal , যা showEditModal পায় রাষ্ট্রের সম্পত্তি।
  • showPrescriptionModal , যা showPrescriptionModal পায় রাষ্ট্রের সম্পত্তি।
  • Prescription , যা রাষ্ট্র থেকে প্রেসক্রিপশনের তালিকা পায়।
  • showPrescriptionId , যা showPrescriptiond পায় রাষ্ট্রের সম্পত্তি।
  • editPrescriptionId , যা editPrescriptionId পায় রাষ্ট্রের সম্পত্তি।

প্রেসক্রিপশন উপাদান

এই উপাদানটি PrescriptionList থেকে একটি প্রপ হিসাবে প্রেসক্রিপশন আইডি পাবে উপাদান. getPrescriptionById এর মাধ্যমে সংশ্লিষ্ট ID সহ একটি প্রেসক্রিপশন আনতে আইডি প্রপস ব্যবহার করা হবে getters পদ্ধতি এবং ব্রাউজারে প্রেসক্রিপশন বৈশিষ্ট্য রেন্ডার।

নিম্নলিখিত কোড সহ উপাদান ফোল্ডারের ভিতরে Prescription.vue তৈরি করুন:

//src/components/Prescription.vue
<template>
  <div class="modal is-active">
    <div class="modal-background"></div>
    <div class="modal-content">
      <h1>VIEW PRESCRIPTION</h1>
      <div class="card">
        <div class="card-content">
          <div class="media">
            <div class="media-content">
              <p class="title is-4">Livestock: {{ prescription.livestock }}</p>
              <p class="subtitle is-6"><b>Prescribed by:</b> {{ prescription.prescribed_by }}</p>
              <p class="subtitle is-6"><b>Disease:</b> {{ prescription.disease }}</p>
            </div>
          </div>
          <div class="content">
            <p class="subtitle is-6">Prescription: {{ prescription.vet_prescription }}</p>
          </div>
        </div>
      </div>
    </div>
    <button class="modal-close is-large" @click="closeModal" aria-label="close"></button>
  </div>
</template>
<script lang="ts">
import { computed } from "vue";
import { useStore } from "@/store";
import { MutationType } from "@/store/mutations";
export default {
  name: "PrescriptionModal",
  props: {
    id: { type: Number, required: true },
  },
  setup(props: any) {
    const store = useStore();
    const prescription = computed(() => store.getters.getPrescriptionById(Number(props.id)));
    const closeModal = () => {
      store.commit(MutationType.SetPrescriptionModal, {
        showModal: false,
        prescriptionId: undefined,
      });
    };
    return { closeModal, prescription };
  },
};
</script>
<style scoped>
h1 {
  color: #ffffff;
  text-align: center;
  font-size: 2rem;
  margin-bottom: 3rem;
}
</style>

closeModal পদ্ধতি SetPrescriptionModal কমিট করে মিউটেশন, যা showModal সেট করে রাজ্যে সম্পত্তি মিথ্যা, যখন Prescription গণনাকৃত সম্পত্তি getPrescriptionById কল করে getter method to retrieve a prescription by its Id.

CreateModal Component

This component is responsible for creating prescriptions.

Create CreateModal.vue inside the components folder with the following code:

//src/components/CreateModal.vue
<template>
  <div class="modal is-active">
    <div class="modal-background"></div>
    <div class="modal-content">
      <form @submit.prevent="createPrescription">
        <div class="field">
          <label class="label">Prescribed By</label>
          <div class="control">
            <input v-model="prescribedBy" class="input" type="text" placeholder="Enter prescriber's name" />
          </div>
        </div>
        <div class="field">
          <label class="label">Prescription</label>
          <div class="control">
            <textarea v-model="prescription" class="textarea" placeholder="Enter prescription"></textarea>
          </div>
        </div>
        <div class="field">
          <label class="label">Disease</label>
          <div class="control">
            <input v-model="disease" class="input" type="text" placeholder="Enter name of disease" />
          </div>
        </div>
        <div class="field">
          <label class="label">Livestock</label>
          <div class="control">
            <input v-model="livestock" class="input" type="text" placeholder="Enter livestock" />
          </div>
        </div>
        <div class="field is-grouped">
          <div class="control">
            <button type="submit" class="button is-link">Submit</button>
          </div>
          <div class="control" @click="closeModal">
            <button class="button is-link is-light">Cancel</button>
          </div>
        </div>
      </form>
    </div>
    <button class="modal-close is-large" @click="closeModal" aria-label="close"></button>
  </div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
import { useStore } from "@/store";
import { Data } from "@/store/state";
import { MutationType } from "@/store/mutations";
import { ActionTypes } from "@/store/actions";
export default {
  name: "CreateModal",
  setup() {
    const state = reactive({
      prescription: "",
      prescribedBy: "",
      disease: "",
      livestock: "",
    });
    const store = useStore();
    const createPrescription = () => {
      if (state.prescription === "" || state.prescribedBy === "" || state.disease === "" || state.livestock === "") return;
      const prescription: Data = {
        vet_prescription: state.prescription,
        prescribed_by: state.prescribedBy,
        disease: state.disease,
        livestock: state.livestock,
      };
      store.dispatch(ActionTypes.CreatePrescription, prescription);
      state.prescription = "";
      state.prescribedBy = "";
      state.disease = "";
      state.livestock = "";
    };
    const closeModal = () => {
      store.commit(MutationType.SetCreateModal, false);
    };
    return { closeModal, ...toRefs(state), createPrescription };
  },
};
</script>

The createPrescription method dispatches an action that makes a post request to the server, thereby creating a new prescription, while the closeModal method commits the SetPrescriptionModal mutation (which sets the showModal property in the state to false).

Working with forms and input element requires two-way data binding, and as such, we used Vue 3’s reactive method to store values used in the input fields.

Note:When using reactive , we need to use toRefs to convert the reactive object to a plain object, where each property on the resulting object is a ref pointing to the corresponding property in the original object.

EditModal Component

This component is responsible for updating prescriptions. Its logic is similar to the CreatePrescription component we discussed in the previous section.

Create EditModal.vue inside the components folder with the following code:

//src/components/EditModal.vue
<template>
  <div class="modal is-active">
    <div class="modal-background"></div>
    <div class="modal-content">
      <form @submit.prevent="updatePrescription">
        <h1>Edit Modal</h1>
        <div class="field">
          <label class="label">Prescribed By</label>
          <div class="control">
            <input v-model="prescribedBy" class="input" type="text" placeholder="Enter prescriber's name" />
          </div>
        </div>
        <div class="field">
          <label class="label">Prescription</label>
          <div class="control">
            <textarea v-model="prescription" class="textarea" placeholder="Enter Prescription"></textarea>
          </div>
        </div>
        <div class="field">
          <label class="label">Disease</label>
          <div class="control">
            <input v-model="disease" class="input" type="text" placeholder="Enter name of disease" />
          </div>
        </div>
        <div class="field">
          <label class="label">Livestock</label>
          <div class="control">
            <input v-model="livestock" class="input" type="text" placeholder="Enter livestock" />
          </div>
        </div>
        <div class="field is-grouped">
          <div class="control">
            <button type="submit" class="button is-link">Submit</button>
          </div>
          <div class="control" @click="closeModal">
            <button class="button is-link is-light">Cancel</button>
          </div>
        </div>
      </form>
    </div>
    <button class="modal-close is-large" @click="closeModal" aria-label="close"></button>
  </div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, computed, onMounted } from "vue";
import { useStore } from "@/store";
import { Prescription } from "@/store/state";
import { MutationType } from "@/store/mutations";
import { ActionTypes } from "@/store/actions";
export default {
  name: "EditModal",
  props: {
    id: { type: Number, required: true },
  },
  setup(props: any) {
    const state = reactive({
      prescription: "",
      prescribedBy: "",
      disease: "",
      livestock: "",
    });
    const store = useStore();
    const setFields = () => {
      const prescription = store.getters.getPrescriptionById(Number(props.id));
      if (prescription) {
        console.log("prescription si kolo", prescription);
        state.prescription = prescription.vet_prescription;
        state.prescribedBy = prescription.prescribed_by;
        state.disease = prescription.disease;
        state.livestock = prescription.livestock;
      }
    };
    onMounted(() => {
      setFields();
    });
    const updatePrescription = () => {
      if (state.prescription === "" || state.prescribedBy === "" || state.disease === "" || state.livestock === "") return;
      const prescription: Prescription = {
        id: props.id,
        vet_prescription: state.prescription,
        prescribed_by: state.prescribedBy,
        disease: state.disease,
        livestock: state.livestock,
        completed: false,
        editing: false,
      };
      store.dispatch(ActionTypes.UpdatePrescription, prescription);
      state.prescription = "";
      state.prescribedBy = "";
      state.disease = "";
      state.livestock = "";
    };
    const closeModal = () => {
      store.commit(MutationType.SetEditModal, { showModal: false, prescriptionId: undefined });
    };
    return { closeModal, ...toRefs(state), updatePrescription };
  },
};
</script>
<style scoped>
label {
  color: #ffffff;
}
h1 {
  color: #ffffff;
  text-align: center;
  font-size: 2rem;
  margin-bottom: 3rem;
}
</style>

The createPrescription method dispatches an action that makes a put request to the server, thereby updating an existing prescription by its ID, while the closeModal method commits the SetPrescriptionModal mutation that sets the showModal property in the state to false. Calling the setFields method on the onMounted lifecycle hook triggers the getPrescriptionById getters method to fetch a prescription from the store by its ID and then updates the properties in the reactive object with the fetched prescription properties as soon as the component is mounted on the DOM.

Launching the Final Project

In the root directory of your Rails API server, run the following command to start the server:

rails server

Now, you can run the frontend application with the following command:

npm run serve

Finally, your application should be as follows:

Vue, Vuex এবং Rails সহ একটি সম্পূর্ণ-স্ট্যাক অ্যাপ্লিকেশন তৈরি করা

উপসংহার

We have built a CRUD API server with Rails and our frontend application on Vue 3 composition API and Vuex, all running on different servers while integrating both stacks to build a fullstack web application. I hope you have learned a great deal from this tutorial. Please reach out in the comment section below if you have any questions or suggestions. Here is the GitHub repo for the full-stack application built in this tutorial.


  1. রেলের সাথে Tailwind CSS ব্যবহার করা

  2. Vue, Vuex এবং Rails সহ একটি সম্পূর্ণ-স্ট্যাক অ্যাপ্লিকেশন তৈরি করা

  3. রেলের সাথে কৌণিক ব্যবহার 5

  4. Nuxt 3 এবং সার্ভারলেস রেডিস দিয়ে শুরু করা