কম্পিউটার

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা

যে কোম্পানিগুলি তাদের অ্যাপ্লিকেশনগুলির সম্পূর্ণ ফ্রন্ট-এন্ড সাইড তৈরি করে তারা প্রায়শই একই ফ্রেমওয়ার্ক বেছে নেয়, যেমন রেল, ব্যাক-এন্ড তৈরি করতে। বহু বছর ধরে, এটি সেরা এবং সবচেয়ে নির্ভরযোগ্য বিকল্প।

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

প্রতিক্রিয়া ফ্রন্ট-এন্ড প্যাঞ্জিয়ার টাইটান হয়ে উঠেছে। আপনি যদি Ruby on Rails এর সাথে কাজ করেন, তাহলে সম্ভাবনা হল যে আপনাকে একবার ডিফল্ট রেল পৃষ্ঠাগুলিকে প্রতিক্রিয়া কোডে (বা অন্য কোন ফ্রন্ট ফ্রেমওয়ার্ক) পরিবর্তন করতে হবে। সম্ভবত, আপনি কেবল Rails + প্রতিক্রিয়া বৈশিষ্ট্যগুলি পছন্দ করেন এবং একটি একক অ্যাপে উভয় প্রযুক্তির শক্তিকে একীভূত করতে পছন্দ করেন৷

এবং, এটা ঠিক আছে! এই নিবন্ধটির লক্ষ্য একটি বাস্তব-বিশ্বের উদাহরণ অন্বেষণ করা:একটি CRUD অ্যাপ্লিকেশন যা বিয়ার পণ্যগুলির একটি তালিকা পরিচালনা করে৷ এটি প্রাথমিকভাবে রেলের সাহায্যে তৈরি করা হবে, এবং তারপরে আরও একত্রিত হতে প্রতিক্রিয়া সহ একটি নতুন ফ্রন্ট-এন্ড তৈরি করা হবে।

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা বিয়ার CRUD অ্যাপ্লিকেশন।

কয়েক ধাপে, আপনি React-এর মূল অংশগুলি বুঝতে পারবেন, Rails কীভাবে এটিকে আলিঙ্গন করে এবং কীভাবে আপনি আপনার ভবিষ্যত প্রকল্পগুলিতে Rails এবং React উভয়ই একীভূত করা শুরু করতে পারেন।

সেটআপ

পূর্বশর্ত হিসাবে, আপনার রুবি (এবং রেল), Node.js এবং সুতার সাথে একটি পরিবেশ সেট আপ করতে হবে।

আপনি সামনের প্যাকেজগুলি পরিচালনা করার জন্য npm পছন্দ করতে পারেন, তবে আমরা সরলতার জন্য সুতার সাথে লেগে থাকব।

আপনার পছন্দের একটি ফোল্ডারে, নিম্নলিখিত কমান্ডটি চালান:

rails new crud-rails-react

এটি আমাদের রেল প্রকল্প শুরু করবে। তারপর, আপনার IDE-তে তৈরি করা প্রকল্পটি খুলুন এবং সরাসরি Gemfile-এ যান .

আমাদের একটি বাগ ঠিক করতে হবে যা এই কমান্ডটি SQLite রত্নটির জন্য তৈরি করে। সুতরাং, sqlite3 সনাক্ত করা নিশ্চিত করুন রত্ন এবং এটিকে নিম্নলিখিতগুলিতে পরিবর্তন করুন:

gem 'sqlite3', '~> 1.3.10'

এটি ডেটাবেস সংস্করণ সম্পর্কিত কিছু পরিচিত ত্রুটি প্রতিরোধ করবে যেহেতু আমরা CRUD উদাহরণের জন্য ডিফল্ট ডাটাবেস হিসাবে SQLite ব্যবহার করব৷

চিন্তা করবেন না, যদিও; অন্যান্য ডাটাবেসে, এই সমস্যাটি ঘটবে না।

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

আমি সাধারণত বেস থেকে উপরের স্তর পর্যন্ত জিনিসগুলি তৈরি করতে পছন্দ করি, তাই আসুন ডাটাবেস মডেলগুলি তৈরি করা শুরু করি৷

আমাদের শুধুমাত্র একটি প্রয়োজন হবে, তাই টাস্কের জন্য রেল স্ক্যাফোল্ডিংয়ের চেয়ে ভাল কমান্ড বৈশিষ্ট্য আর নেই:

rails g scaffold Beer brand:string style:string country:string quantity:integer & rake db:migrate

এই মডেলটি বেশ মৌলিক, তাই আপনি যাওয়ার সাথে সাথে অন্যান্য বৈশিষ্ট্য এবং প্রকারগুলি যোগ করতে দ্বিধা বোধ করুন৷

db/migrate-এর মধ্যে ফোল্ডারে, “_create_beers.rb এ শেষের নামের একটি নতুন ফাইল আছে ” এটি সেই রেকর্ড যা রেল আমাদের জন্য একটি বিয়ারের প্রতিনিধিত্ব করার জন্য তৈরি করেছে৷

মডেলটি, পরিবর্তে, অ্যাপ/মডেল-এর অধীনে তৈরি করা হবে ফোল্ডার সেগুলি যেমন আছে তেমনই রেখে দিন এবং db/seeds.rb-এ কোডের নিম্নলিখিত লাইনগুলি যোগ করুন ফাইল:

Beer.create(brand: 'Double Stout', style: 'Stout', country: 'England', quantity: 54)
Beer.create(brand: 'Spaten', style: 'Helles', country: 'Germany', quantity: 3)
Beer.create(brand: 'Newcastle', style: 'Brown ale', country: 'UK', quantity: 12)

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

rake db:seed

এটাই! এখন, আপনার টেবিলে কিছু বিয়ার আছে .

ওয়েবপ্যাকার সেটআপ

ওয়েবপ্যাকার জাভাস্ক্রিপ্ট অ্যাপ্লিকেশনগুলির জন্য সর্বাধিক ব্যবহৃত স্ট্যাটিক মডিউল বান্ডলারগুলির মধ্যে একটি। এই কারণে, এটি একটি বিদ্যমান অ্যাপ্লিকেশনে প্রতিক্রিয়া ক্ষমতাগুলিকে অন্তর্ভুক্ত করার জন্য নিখুঁত ম্যাচ৷

রেলগুলি আমাদেরকে একটি ওয়েবপ্যাকার বান্ডলার প্রদান করে যা রেলের মধ্যে জাভাস্ক্রিপ্ট-সদৃশ অ্যাপ্লিকেশনগুলি পরিচালনা করতে সম্পূর্ণরূপে অভিযোজিত৷

এটি ইনস্টল করতে, আপনার Gemfile-এ একটি দ্বিতীয় লাইন যোগ করুন , নিম্নরূপ:

gem 'webpacker', '~> 4.3.x'

দারুণ! এটিই একমাত্র রত্ন যা আমাদের পুরো অ্যাপ ডেভেলপমেন্টের জন্য যোগ করতে হবে। এটি শুধুমাত্র সম্ভব কারণ আমরা সুতার সামনের দায়িত্বগুলি অর্পণ করছি, যা এই নিবন্ধে পরে সেট করা হবে৷

এখন, নিম্নলিখিত কমান্ডগুলি জারি করে আপডেটগুলি ইনস্টল করার সময় এসেছে:

bundle install
bundle exec rake webpacker:install
bundle exec rake webpacker:install:react

প্রথমটি বেশিরভাগ রেল ডেভেলপারদের দ্বারা সুপরিচিত। আমরা ওয়েবপ্যাকার নিজেই সহ সমস্ত নির্ভরতা ইনস্টল করছি।

ওয়েবপ্যাকার ইনস্টল হয়ে গেলে, আমরা ওয়েবপ্যাকার নির্ভরতা, সেইসাথে প্রতিক্রিয়াগুলি ইনস্টল করতে রেকের মাধ্যমে এর কমান্ডগুলি অনুকরণ করতে পারি।

এটি একটি অত্যন্ত গুরুত্বপূর্ণ পদক্ষেপ কারণ এখানেই ওয়েবপ্যাকার নিশ্চিত করবে যে আপনার সমস্ত জাভাস্ক্রিপ্ট নির্ভরতা সঠিকভাবে একটি রেল পরিবেশে সেট করা আছে, তাই এটি এড়িয়ে যাবেন না বা সরাসরি চালানোর চেষ্টা করবেন না যেমন আপনি সাধারণত এনপিএম বা ইয়ার্ন দিয়ে করেন, ঠিক আছে?

কমান্ড সম্পূর্ণ হলে, কয়েকটি ফোল্ডার এবং ফাইল (যেমন node_modules এবং package.json )ও তৈরি করা হবে৷

ফ্রন্ট-এন্ড সেটআপ

আমরা এখন পর্যন্ত যে সমস্ত সেটিংস করেছি তা CRUD অ্যাপ্লিকেশনটি শুধুমাত্র Rails এর সাথে কাজ করার জন্য যথেষ্ট। আপনি যদি rails s এর মাধ্যমে রেল সার্ভার শুরু করেন কমান্ড, এটি ফলাফল হবে:

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা রেল স্বয়ংক্রিয়ভাবে তৈরি বিয়ার CRUD।

যাইহোক, আমরা প্রতিক্রিয়া সহ আমাদের নিজস্ব CRUD চাই।

প্রথমে, আপনাকে নিশ্চিত করতে হবে যে সমস্ত প্রয়োজনীয় ফ্রন্ট-এন্ড নির্ভরতা সুতার মাধ্যমে কনফিগার করা হয়েছে:

  • প্রতিক্রিয়া করুন
  • প্রতিক্রিয়া অ্যাপে নেভিগেশন মোকাবেলা করতে প্রতিক্রিয়া রাউটার
  • ব্যবহারের জন্য প্রস্তুত প্রতিক্রিয়া উপাদানগুলির জন্য পিঁপড়ার নকশা

এন্ট ডিজাইন (এন্টডি নামে পরিচিত) এন্টারপ্রাইজ-স্তরের অ্যাপ্লিকেশনের জন্য একটি সমৃদ্ধ ওপেন সোর্স লাইব্রেরি। এটি অত্যন্ত কাস্টমাইজযোগ্য প্রতিক্রিয়া উপাদানগুলির একটি গুচ্ছ সরবরাহ করে যা ওয়েব অ্যাপগুলির বিকাশকে অনেক সহজ করে তোলে৷

সবকিছু ইনস্টল করার জন্য, নিম্নলিখিত কমান্ডটি চালান:

yarn add antd react-router-dom

আমাদের স্পষ্টভাবে react যোগ করার দরকার নেই react-router-dom থেকে লাইব্রেরি এটা করবে।

এই সময়ে, আপনি যখন package.json খুলবেন ফাইল, এটি স্বয়ংক্রিয়ভাবে তৈরি সামগ্রী হবে:

{
  "dependencies": {
    "@babel/preset-react": "^7.12.1",
    "@rails/webpacker": "4.3.0",
    "antd": "^4.7.2",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "prop-types": "^15.7.2",
    "react": "^17.0.0",
    "react-dom": "^17.0.0",
    "react-router-dom": "^5.2.0"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.11.0"
  }
}

এটি একটি Rails-React কম্বোর জন্য সবচেয়ে মৌলিক সেটআপ। সুতরাং, আমরা কোডে এগিয়ে যেতে ভাল।

রেল সাইড মানিয়ে নেওয়া

সামনের দিকে যাওয়ার আগে রেলের দিকে কিছু গুরুত্বপূর্ণ কাজ করতে হবে।

প্রথমত, আমাদের কন্ট্রোলারকে সংজ্ঞায়িত করতে হবে যা পৃষ্ঠা পুনঃনির্দেশকে কেন্দ্রীভূত করবে। যেহেতু আমরা একটি একক-পৃষ্ঠা অ্যাপ্লিকেশন (SPA) তৈরি করছি, শুধুমাত্র একটি কন্ট্রোলার প্রয়োজন, যা ইতিমধ্যে তৈরি করা হয়েছে:BeersController .

এটিকে অ্যাপ/কন্ট্রোলারের অধীনে খুলুন ফোল্ডার এবং এর বিষয়বস্তু নিম্নরূপ পরিবর্তন করুন:

class BeersController < ApplicationController
  def index
  end
end

চিন্তা করবেন না; আমরা যে সমস্ত কোড সরিয়েছি তা পরবর্তী কন্ট্রোলারে তৈরি করা হবে।

এই কন্ট্রোলারের একমাত্র কাজ হল রেল থেকে প্রতিক্রিয়া করার জন্য একটি সরাসরি রুট প্রদান করা, যে কারণে আমরা শুধুমাত্র index সেট করছি পদ্ধতি।

এটির সাথে সরাসরি সংযোগ করতে, আসুন routes.rb খুলি config এর অধীনে ফাইল ফোল্ডার এবং এর বিষয়বস্তুকে নিম্নলিখিতগুলিতে পরিবর্তন করুন:

Rails.application.routes.draw do
  root 'beers#index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

নতুন root নোট করুন কনফিগারেশন হ্যাঁ, আমরা মূলের শেষ বিন্দুকে beers-এ ম্যাপ করছি সূচক পদ্ধতি।

এছাড়াও আপনাকে index.html.erb খালি করতে হবে app/views/beers-এর মধ্যে ফাইল ফোল্ডার যেহেতু আমরা রেলওয়ের কোনো ওয়েব কন্টেন্ট রেন্ডার করা চাই না। এটি একটি কৌশল যা আমরা রেলকে শুধুমাত্র প্রতিক্রিয়া কোড প্রদর্শন করতে বাধ্য করতে ব্যবহার করতে পারি।

বিয়ার API

এখন, বিয়ার API তৈরিতে এগিয়ে যাওয়া যাক। API গঠন কার্যত BeersController এর মতই হবে কিন্তু কিছু সামান্য পরিবর্তন সঙ্গে. এটি তৈরি করতে, নিম্নলিখিত কমান্ডটি চালান:

rails generate controller api/v1/Beers

একটি সংস্করণ সিস্টেম ব্যবহার করে এটি তৈরি করা নিশ্চিত করুন। এটি আপনাকে ভবিষ্যতে আপনার API বিকশিত করতে এবং এটিকে সাধারণ কন্ট্রোলার থেকে আলাদা করার অনুমতি দেবে৷

এখন, app/controllers/api/v1/beers_controller.rb খুলুন ফাইল করুন এবং কোডটি নিম্নলিখিত দিয়ে প্রতিস্থাপন করুন:

class Api::V1::BeersController < ApplicationController
  before_action :set_beer, only: [:show, :edit, :update, :destroy]

  # GET /beers
  # GET /beers.json
  def index
    @beers = Beer.all.order(brand: :asc)
    render json: @beers
  end

  # GET /beers/1
  # GET /beers/1.json
  def show
    if @beer
      render json: @beer
    else
      render json: @beer.errors
    end
  end

  # GET /beers/new
  def new
    @beer = Beer.new
  end

  # GET /beers/1/edit
  def edit
  end

  # POST /beers
  # POST /beers.json
  def create
    @beer = Beer.new(beer_params)


    if @beer.save
      render json: @beer
    else
      render json: @beer.errors
    end
  end

  # PATCH/PUT /beers/1
  # PATCH/PUT /beers/1.json
  def update
  end

  # DELETE /beers/1
  # DELETE /beers/1.json
  def destroy
    @beer.destroy

    render json: { notice: 'Beer was successfully removed.' }
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_beer
      @beer = Beer.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def beer_params
      params.permit(:brand, :style, :country, :quantity)
    end
end

বেশিরভাগ অপারেশন পূর্ববর্তী কন্ট্রোলার থেকে পুনর্ব্যবহার করা হয়েছিল।

before_action স্নিপেট id অনুযায়ী সঠিক বিয়ার বস্তু পুনরুদ্ধারের যত্ন নেবে অনুরোধের মধ্যে প্যারামিটার। :only-এর পরে অ্যারেতে রাখা অপারেশনগুলি দফা এই স্বয়ংক্রিয় পুনরুদ্ধার বৈশিষ্ট্য প্রয়োজন হবে.

বাকি পদ্ধতিগুলো CRUD এর প্রতিটি অপারেশনের সমতুল্য। আপনার অনুরোধের প্রতিক্রিয়া হিসাবে সর্বদা JSON ফেরত দেওয়ার কথা মনে রাখবেন কারণ এটিই আমরা আমাদের প্রতিক্রিয়া উপাদানগুলির মধ্যে ব্যবহার করব।

অবশেষে, আপনাকে config/routes.rb মানিয়ে নিতে হবে আবার নতুন তৈরি রুট অন্তর্ভুক্ত করতে. সুতরাং, ফাইলের বিষয়বস্তুগুলিকে নিম্নলিখিতগুলিতে পরিবর্তন করতে ভুলবেন না:

Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      get 'beers/index'
      post 'beers/create'
      delete 'beers/:id', to: 'beers#destroy'
    end
  end

  root 'beers#index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

ধ্বংস রুট দেখায় কিভাবে destroy এ ম্যাপ করতে হয় পদ্ধতি যদি এটি স্পষ্টভাবে পাথের মধ্যে সেট করা না থাকে।

প্রতিক্রিয়া উপাদান

প্রতিক্রিয়া উপাদানগুলির মাধ্যমে কাজ করে, যা একটি ওয়েব অ্যাপ্লিকেশনের বিল্ডিং ব্লকের মতো কাজ করে। প্রত্যেকে এক বা একাধিক কাজ করে যা একটি প্রসঙ্গ হিসাবে বোঝা যায়।

সংক্ষেপে, একটি কম্পোনেন্ট একটি জাভাস্ক্রিপ্ট ক্লাস বা ফাংশন দিয়ে তৈরি যা প্যারামিটার হিসাবে বৈশিষ্ট্যগুলি গ্রহণ করতে পারে, এর মধ্যে ব্যবসায়িক যুক্তি প্রক্রিয়া করতে পারে এবং শেষ পর্যন্ত, স্ক্রিনের একটি অংশকে প্রতিনিধিত্ব করে একটি কার্যকরী UI উপাদান ফেরত দিতে পারে৷

পরবর্তী উদাহরণগুলি থেকে নেওয়া নিম্নলিখিত কোড স্নিপেটটি নিন যা আমরা তৈরি করব:

<Layout>
  <Header />
  <Content>...</Content>
  <Footer>Honeybadger ©2020.</Footer>
</Layout>

হ্যাঁ, প্রতিক্রিয়া উপাদানগুলি JSX (JavaScript XML) নামক একটি কাস্টম মার্কআপ ভাষা ব্যবহার করে যা HTML এর সাথে ঘনিষ্ঠভাবে সাদৃশ্যপূর্ণ। সমস্ত HTML ট্যাগ JSX ফাইলের মধ্যেও পাওয়া যায়। আপনি এখানে JSX সম্পর্কে আরও পড়তে পারেন।

উপরের উদাহরণটি ব্যাখ্যা করে কিভাবে antd একটি স্ট্রাকচারাল লেআউট উপাদান নিয়ে কাজ করে। উপাদানগুলি অন্যান্য উপাদান থেকে তৈরি করা হয় এবং একে অপরের উপরে স্ট্যাক করা হয়, একটি সম্পূর্ণ রচনা করে। কিছু বৈশিষ্ট্যগুলি গ্রহণ করে (ঐচ্ছিক বা না), এবং কিছু অভ্যন্তরীণ বিষয়বস্তু থাকতে পারে৷

উপাদানগুলি ক্লাস- বা ফাংশন-ভিত্তিক হতে পারে।

ক্লাস উপাদান

ক্লাস-ভিত্তিক উপাদানগুলি সাধারণ জাভাস্ক্রিপ্ট ক্লাস হিসাবে তৈরি করা হয়, যেমন নীচে দেখানো হয়েছে:

class Beers extends React.Component {}

তারা React.Component থেকে উত্তরাধিকার সূত্রে প্রাপ্ত ক্লাস, একটি জীবনচক্র আছে, এবং প্রাথমিককরণ, রেন্ডারিং এবং পর্যায়গুলি ধ্বংস করার আগে কোড চালানোর জন্য ব্যবহার পদ্ধতি প্রদান করে৷

যাইহোক, সবচেয়ে গুরুত্বপূর্ণ (এবং প্রয়োজনীয়) পদ্ধতি হল render() , যা প্রতিবার কম্পোনেন্ট আপডেট করার সময় বলা হয়।

কার্যকরী উপাদান

কার্যকরী উপাদানগুলি ES6 এর তীর ফাংশন ব্যবহার করে এবং সিনট্যাক্স এবং জটিলতার পরিপ্রেক্ষিতে প্রতিক্রিয়া উপাদানগুলিকে সরল করে৷

একই beers উপরের উপাদানটি একটি ফাংশনে নিম্নরূপ উপস্থাপন করা হবে:

const Beers = () => <div>My Beers</div>;

এটা অনেক সহজ, তাই না?

প্রতিক্রিয়া সেট আপ করা

আমরা ইতিমধ্যে রেল সূচক পৃষ্ঠা খালি করেছি। এখন, আমরা রেলগুলিকে জানাব যে এটিকে এর ডিফল্ট ফ্রন্ট-এন্ড প্রতিক্রিয়া তৈরি করতে হবে।

এটি অর্জন করতে, আপনাকে &lt;head>-এ কোডের নিম্নলিখিত লাইন যোগ করতে হবে আপনার app/views/layouts/application.html.erb এর ট্যাগ ফাইল:

<%= javascript_pack_tag 'index' %>

এটি আমাদের অ্যাপ্লিকেশন হেডারে জাভাস্ক্রিপ্ট প্যাক যোগ করবে, যার ফলে সমস্ত জাভাস্ক্রিপ্ট ফাইল, প্রতিক্রিয়া সহ, সূচীপত্র-এর মধ্যে কার্যকর করা হবে। পৃষ্ঠা।

আমাদের নিশ্চিত করতে হবে যে index.jsx ফাইলটির একই নাম রয়েছে যেহেতু এটি আমদানি প্যাকের দিকে নির্দেশিত।

এই উদ্দেশ্যে, আসুন অটোজেনারেটেড app/javascript/packs/hello_react.jsx এর নাম পরিবর্তন করি index.jsx এ ফাইল করুন .

তারপর, কোডটি নিম্নলিখিত দিয়ে প্রতিস্থাপন করুন:

import React from "react";
import { render } from "react-dom";
import App from "../components/App";

document.addEventListener("DOMContentLoaded", () => {
  render(<App />, document.body.appendChild(document.createElement("div")));
});

এই ফাইলটিকে রিঅ্যাক্ট অ্যাপ্লিকেশন ফাইলের জন্য ভুল করবেন না, কারণ এটি শুধুমাত্র একটি ফাইল যা ReactDOM এর render এর মাধ্যমে DOM-এ সম্পূর্ণ React অ্যাপের শ্রেণিবিন্যাস লোড করবে। ফাংশন।

সাধারণত, প্রতিটি প্রতিক্রিয়া অ্যাপ্লিকেশন একটি index.js থেকে শুরু হয় ফাইল যা প্রয়োজনীয় সমস্ত কিছু লোড করে, প্রতিক্রিয়া নিজেই সহ।

App ট্যাগ আমাদের অনুক্রমের শীর্ষ উপাদান মানচিত্র. সুতরাং, আসুন এটিকে index.jsx হিসাবে তৈরি করি javascript/components এর অধীনে ফোল্ডার (ফোল্ডারগুলি ম্যানুয়ালি তৈরি করুন যদি সেগুলি এখনও বিদ্যমান না থাকে) এবং এতে নিম্নলিখিত কোডটি রাখুন:

import React from "react";
import Routes from "../routes/index";
import "antd/dist/antd.css";

export default () => <>{Routes}</>;

বিকল্পভাবে, আপনি index.jsx-এর মধ্যে antd CSS ফাইল আমদানি করতে পারেন . উভয় পদ্ধতিই কাজ করবে।

রুটের তালিকা রুট এর অধীনে রাখা হয়েছে ফোল্ডার এগুলি রিঅ্যাক্ট রাউটার লাইব্রেরি থেকে নেওয়া হয়েছে, যা আমাদের জন্য বেশিরভাগ কঠোর পরিশ্রম করে। এটি এর বিষয়বস্তু:

import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Home from "../components/Home";

export default (
  <Router>
    <Switch>
      <Route path="/" exact component={Home} />
    </Switch>
  </Router>
);

আপনার প্রতিটি রুট একটি ভিন্ন Route এর মধ্যে ম্যাপ করা আবশ্যক ট্যাগ path পরামিতি অবশ্যই প্রতিটি রুট এন্ডপয়েন্টের URI-এর সাথে মিলবে, যখন component প্যারাম সেই উপাদানটিকে নির্দেশ করে যেটিতে প্রতিক্রিয়া রাউটার অনুরোধটি পুনঃনির্দেশ করবে।

মনে রাখবেন যে আমাদের এসপিএর জন্য আমাদের একটি একক রুট থাকবে। আপনি যদি একটি /বিয়ার্স ম্যাপ করতে চান তাহলে আপনি এখানে অন্যান্য পথ যোগ করতে পারেন বিয়ারের তালিকার জন্য, উদাহরণস্বরূপ, তবে আমরা এটিকে সহজ রাখব।

এছাড়াও, মনে রাখবেন যে আমরা Home আমদানি করছি এখানে উপাদান, যা এখনও বিদ্যমান নেই। সুতরাং, আসুন এটিকে Home.jsx হিসাবে তৈরি করি উপাদানের অধীনে ফোল্ডার তারপরে, এতে নিম্নলিখিত কোড যোগ করুন:

import { Layout } from "antd";
import React from "react";
import Beers from "./Beers";
import Header from "./Header";

const { Content, Footer } = Layout;

export default () => (
  <Layout className="layout">
    <Header />
    <Content style={{ padding: "0 50px" }}>
      <div className="site-layout-content" style={{ margin: "100px auto" }}>
        <h1>Beer Catalog</h1>
        <Beers />
      </div>
    </Content>
    <Footer style={{ textAlign: "center" }}>Honeybadger ©2020.</Footer>
  </Layout>
);

যখন প্রতিক্রিয়া উপাদানগুলির কথা আসে, আমি সেগুলি উপরে থেকে নীচে তৈরি করতে পছন্দ করি। এইভাবে, অ্যাপটিকে সামগ্রিকভাবে কাজ করার জন্য আপনি সমস্ত প্রয়োজনীয় উপাদানগুলির উপর সামগ্রিকভাবে নজর রাখতে পারেন৷

হোম কম্পোনেন্ট একটি অ্যাসেম্বলারের মতো আচরণ করে; এটি অ্যাপের অন্যান্য সমস্ত উপাদানের অংশগুলিকে মিটমাট করে, যেমন Layout , Header , Content, এবং Footer .

এই টুকরাগুলির প্রতিটি কোথা থেকে আসছে তা সঠিকভাবে আলাদা করা গুরুত্বপূর্ণ। আপনার স্ক্রীন রচনা করতে Antd একগুচ্ছ প্রস্তুত উপাদান প্রদান করে, যেমন লেআউট, বিষয়বস্তু এবং ফুটার।

এগুলি প্রাথমিকভাবে পৃষ্ঠার অংশগুলির কাঠামোর উপর দৃষ্টি নিবদ্ধ করে, তবে কিছু বিল্ট-ইন CSS শৈলীও অফার করে, যা আমাদের আরও ভাল চেহারা দিয়ে উপকৃত করবে।

শিরোনাম উপাদান

Header.jsx কম্পোনেন্ট ফাইল, যা javascript/components-এর মধ্যেও তৈরি করা উচিত ফোল্ডার, হেডারের বিষয়বস্তু রাখবে। এটিতে একটি সাধারণ antd মেনু এবং Honeybadger লোগো সহ একটি div রয়েছে, যা নীচে দেখানো হয়েছে:

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা Antd মেনু আইটেম।

নীচে, আপনি Header.jsx-এ রাখার জন্য কোডটি খুঁজে পেতে পারেন :

import React from "react";
import { Layout, Menu } from "antd";

const { Header } = Layout;

export default () => (
  <Header>
    <div className="logo" />
    <Menu theme="dark" mode="horizontal" defaultSelectedKeys={["1"]}>
      <Menu.Item key="1">Home</Menu.Item>
      <Menu.Item key="2">Our Services</Menu.Item>
      <Menu.Item key="3">Contact</Menu.Item>
    </Menu>
  </Header>
);

Antd মেনু উপাদানটি ব্যবহার করা বেশ সহজ কিন্তু উপলব্ধ কাস্টমাইজেশন বিকল্পগুলির পরিপ্রেক্ষিতে বিস্তৃত, যা আমাদের তৈরি করতে দেয়, উদাহরণস্বরূপ, নেভিগেশন ড্রয়ার, ড্রপ-ডাউন, গ্রুপ এবং সাবগ্রুপ।

মনে রাখবেন যে আমরা defaultSelectedKeys প্রদান করছি , একটি অ্যারে যা মেনুকে বলে যে কোন আইটেমগুলি সক্রিয়৷

আমাদের মেনু কোথাও নেভিগেট করবে না; তারা শুধুমাত্র চেহারা এবং অনুভূতি পূরণ করতে পর্দা দখল করবে. সুতরাং, চলুন Beers-এ এগিয়ে যাই উপাদান।

The Beers Component

এই উপাদানটি বিয়ারের তালিকা এবং টেবিলের মধ্যে উপলব্ধ অ্যাকশনগুলির উপর দৃষ্টি নিবদ্ধ করে, যেমন মুছে ফেলা, ডেটা পেজিনেশন এবং টেবিল পুনরায় লোড করা।

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা প্রতিক্রিয়া ক্রিয়া এবং উপাদানগুলির ভিজ্যুয়াল উপস্থাপনা৷

উপরের ছবিটি দেখে নিন। আমরা উপাদান এবং ক্রিয়াগুলিকে নিম্ন স্তরে ভেঙে দিয়েছি, যাতে আপনি আরও ভালভাবে বুঝতে পারেন এখানে কী করা হবে৷

প্রতিক্রিয়ার অবস্থা

প্রতিক্রিয়া উপাদানগুলি একটি state দিয়ে তৈরি করা হয় বস্তু এই বস্তুটি প্রদত্ত উপাদানের সাথে সরাসরি সংযুক্ত একটি স্টোর হিসাবে কাজ করে। প্রতিটি উপাদানের নিজস্ব state আছে অবজেক্ট, এবং আপনি যখনই স্টেট পরিবর্তন করেন, কম্পোনেন্টটি রি-রেন্ডার করা হয়।

আমাদের Beers এর প্রথম কাজ উপাদান একটি টেবিলে তালিকা প্রদর্শন করা হয়. এই উদ্দেশ্যে, আমাদের এই তালিকাটিকে একটি অ্যারেতে ধরে রাখতে হবে:

state = {
  beers: [],
};

দ্য বিয়ার তালিকা

এই অ্যারে খাওয়ানোর জন্য, আমাদের আগে তৈরি করা API কন্ট্রোলার থেকে তালিকাটি পুনরুদ্ধার করতে হবে। যে ফাংশনটি এটি পুনরুদ্ধার করবে তা পর্যালোচনা করুন:

loadBeers = () => {
  const url = "api/v1/beers/index";
  fetch(url)
    .then((data) => {
      if (data.ok) {
        return data.json();
      }
      throw new Error("Network error.");
    })
    .then((data) => {
      data.forEach((beer) => {
        const newEl = {
          key: beer.id,
          id: beer.id,
          brand: beer.brand,
          style: beer.style,
          country: beer.country,
          quantity: beer.quantity,
        };

        this.setState((prevState) => ({
          beers: [...prevState.beers, newEl],
        }));
      });
    })
    .catch((err) => message.error("Error: " + err));
};

সরলতার স্বার্থে, আমরা যখনই API থেকে ডেটার অনুরোধ করতে চাই তখনই আমরা সমস্ত আধুনিক ব্রাউজারে উপলব্ধ Fetch API ব্যবহার করব৷

উপরের ফাংশনটি API থেকে বিয়ারের অ্যারে পুনরুদ্ধার করতে কয়েকটি পদক্ষেপ নেয়:

  1. এটি প্রথমে /সূচী অনুরোধ করে এন্ডপয়েন্ট অ্যাসিঙ্ক্রোনাসলি এবং then প্রতিক্রিয়া স্থিতি ঠিক আছে সমান কিনা তা পরীক্ষা করে .
  2. যদি তা হয়, আমরা JSON হিসাবে ডেটা ফেরত দিই; অন্যথায়, আসুন একটি Error নিক্ষেপ করি .
  3. then , আমরা আমাদের নিজস্ব বিয়ার অবজেক্ট রচনা করার জন্য ফলাফলের অ্যারের উপর পুনরাবৃত্তি করি এবং রাজ্যের beers যোগ করি অ্যারে।
  4. প্রক্রিয়া চলাকালীন কিছু ভুল হলে, catch ব্লক ব্যতিক্রমটি ক্যাপচার করবে এবং এটি একটি বার্তা সতর্কতা হিসাবে প্রদর্শন করবে৷

চমৎকার, তাই না? এটি প্রায় একই পদক্ষেপ যা আমরা অন্য সব অনুরোধের জন্য গ্রহণ করব।

কিন্তু, কিভাবে antd টেবিলে ডেটা প্রদর্শন করে? ভাল প্রশ্ন! চলুন নিচের কোডটি একবার দেখে নেওয়া যাক:

columns = [
  {
    title: "Brand",
    dataIndex: "brand",
    key: "brand",
  },
  ...{
    title: "",
    key: "action",
    render: (_text, record) => (
      <Popconfirm title="Are you sure to delete this beer?" onConfirm={() => this.deleteBeer(record.id)} okText="Yes" cancelText="No">
        <a href="#" type="danger">
          Delete{" "}
        </a>
      </Popconfirm>
    ),
  },
];

আমি আরও ভাল বোঝার জন্য এটিকে কিছুটা সরল করেছি। এটি একটি অ্যারে যা আমাদের টেবিলের কঙ্কাল প্রতিনিধিত্ব করে। এইভাবে antd টেবিল কাজ করে; তাদের একটি অ্যারে হিসাবে আপনার টেবিল গঠন (সারি এবং কলাম) সম্পর্কে মেটাডেটা তথ্য পেতে হবে।

প্রতিটি কলাম অ্যারের মধ্যে একটি বস্তু, এবং ক্রম এখানে গুরুত্বপূর্ণ। title অ্যাট্রিবিউট কলামের নাম পায়, যখন dataIndex নাম হল প্রতিক্রিয়া উপাদান এবং key এর মধ্যে এটি কীভাবে পরিচিত হবে এটি এর অনন্য শনাক্তকারী।

বেশিরভাগ কলামের জন্য, অ্যাকশন কলাম ব্যতীত কনফিগারেশন একই রকম। সেখানে, ব্যবহারকারী যখন কোনো আইটেম মুছতে চায় তখন ট্রিগার করার জন্য আমাদের কর্মের লিঙ্কটি নির্দিষ্ট করতে হবে। মনে রাখবেন যে আমরা antd-এর Popconfirm কম্পোনেন্ট ব্যবহার করছি।

এটি একটি খুব সুন্দর উপাদান যা ব্যবহারকারীদের একটি অ্যাকশন হওয়ার আগে নিশ্চিত করার জন্য অনুরোধ করার কাজটি সহজ করে। নীচের চিত্রটি এটি দেখতে কেমন তা ব্যাখ্যা করে:

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা মোছার আগে একটি নিশ্চিত ডায়ালগ অনুরোধ করা হচ্ছে।

অ্যাকশন মুছুন

একটি আইটেম মুছে ফেলার জন্য, আমাদের দুটি প্রধান ক্রিয়াকলাপ সম্পাদন করতে হবে:API এ মুছে ফেলার কল এবং টেবিল পুনরায় লোড করা।

ডিলিট ফাংশনটি আমাদের তৈরি করা প্রথম আনার মতো:

deleteBeer = (id) => {
  const url = `api/v1/beers/${id}`;

  fetch(url, {
    method: "delete",
  })
    .then((data) => {
      if (data.ok) {
        this.reloadBeers();
        return data.json();
      }
      throw new Error("Network error.");
    })
    .catch((err) => message.error("Error: " + err));
};

দেখা? এখানে শুধুমাত্র নতুন জিনিস হল HTTP method fetch এর দ্বিতীয় প্যারামিটার হিসাবে পাস করা হয়েছে পদ্ধতি এছাড়াও, then এর মধ্যে ধারা, আমরা reloadBeers বলি ফাংশন, যা আবার ব্যাক-এন্ড থেকে সমস্ত বিয়ার পুনরায় আনবে।

এই ফাংশনের বিষয়বস্তু প্রায় নিম্নরূপ:

reloadBeers = () => {
  this.setState({ beers: [] });
  this.loadBeers();
};

আমরা রাজ্যের beers রিসেট করছি অ্যারে এবং আবার লোড ফাংশন কল করা।

চূড়ান্ত উপাদান

অবশেষে, আমাদের স্পষ্টভাবে antd ট্যাগ কল করে উপাদান রচনা করতে হবে। আসুন দেখি কিভাবে এটি চূড়ান্ত উপাদান কোডের সাথে যায়:

import { Table, message, Popconfirm } from "antd";
import React from "react";
import AddBeerModal from "./AddBeerModal";

class Beers extends React.Component {
  columns = [
    {
      title: "Brand",
      dataIndex: "brand",
      key: "brand",
    },
    {
      title: "Style",
      dataIndex: "style",
      key: "style",
    },
    {
      title: "Country",
      dataIndex: "country",
      key: "country",
    },
    {
      title: "Quantity",
      dataIndex: "quantity",
      key: "quantity",
    },
    {
      title: "",
      key: "action",
      render: (_text, record) => (
        <Popconfirm title="Are you sure to delete this beer?" onConfirm={() => this.deleteBeer(record.id)} okText="Yes" cancelText="No">
          <a href="#" type="danger">
            Delete{" "}
          </a>
        </Popconfirm>
      ),
    },
  ];

  state = {
    beers: [],
  };

  componentDidMount() {
    this.loadBeers();
  }

  loadBeers = () => {
    const url = "api/v1/beers/index";
    fetch(url)
      .then((data) => {
        if (data.ok) {
          return data.json();
        }
        throw new Error("Network error.");
      })
      .then((data) => {
        data.forEach((beer) => {
          const newEl = {
            key: beer.id,
            id: beer.id,
            brand: beer.brand,
            style: beer.style,
            country: beer.country,
            quantity: beer.quantity,
          };

          this.setState((prevState) => ({
            beers: [...prevState.beers, newEl],
          }));
        });
      })
      .catch((err) => message.error("Error: " + err));
  };

  reloadBeers = () => {
    this.setState({ beers: [] });
    this.loadBeers();
  };

  deleteBeer = (id) => {
    const url = `api/v1/beers/${id}`;

    fetch(url, {
      method: "delete",
    })
      .then((data) => {
        if (data.ok) {
          this.reloadBeers();
          return data.json();
        }
        throw new Error("Network error.");
      })
      .catch((err) => message.error("Error: " + err));
  };

  render() {
    return (
      <>
        <Table className="table-striped-rows" dataSource={this.state.beers} columns={this.columns} pagination={{ pageSize: 5 }} />

        <AddBeerModal reloadBeers={this.reloadBeers} />
      </>
    );
  }
}

export default Beers;

এখন, আপনি একসাথে সবকিছু দেখতে পারেন. রেন্ডার ফাংশনটি আমরা সেখানে যে দুটি ট্যাগ আমদানি করছি তা প্রদর্শন করবে:antd এর Table উপাদান এবং AddBeerModal (যে মডেলটি আমরা কয়েক মিনিটের মধ্যে তৈরি করব)।

টেবিলের উপাদানটি অনেক সমৃদ্ধ যেভাবে এটি আমাদেরকে pagination সেট করে ফলাফলের মাধ্যমে স্বয়ংক্রিয়ভাবে পেজিনেট করতে দেয়। বস্তু আমরা এখানে যোগ করছি একমাত্র সম্পত্তি প্রতিটি পৃষ্ঠার আকার (প্রতি পৃষ্ঠায় 5টি ফলাফল)।

dataSource অ্যাট্রিবিউট ব্যাক-এন্ড থেকে আমরা মাউন্ট করা বিয়ারের তালিকা এবং columns গ্রহণ করে অ্যাট্রিবিউট আমাদের ইতিমধ্যে তৈরি করা মেটাডেটা গ্রহণ করে।

AddBeerModal উপাদান

টেবিলের নিচে, আপনি নতুন বিয়ার যোগ করার জন্য একটি বোতাম দেখতে পারেন। যখন আমরা এই বোতামটিতে ক্লিক করি, তখন এটি আমাদের ক্যাটালগে নতুন বিয়ার নিবন্ধন করার জন্য একটি ফর্ম সহ একটি মডেল খুলবে, আপনি নীচে দেখতে পাবেন:

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা ক্যাটালগে নতুন বিয়ার যোগ করা হচ্ছে।

antd কীভাবে ফর্মগুলি পরিচালনা করে তা অন্বেষণ করার এটি একটি দুর্দান্ত উপায়৷

প্রথমে, আসুন এই উপাদানটিতে আমাদের যে ক্রিয়াগুলি থাকবে তা ভেঙে দেওয়া যাক। উল্লেখ্য যে কম্পোনেন্টটি নিজেই দুটি দিয়ে তৈরি:একটি বোতাম এবং একটি মডেল।

এর মানে হল যে আমাদের তাদের উভয়ের সাথে সম্পর্কিত অপারেশন ম্যাপ করতে হবে:

  • showModal এবং handleCancel মোডেল খোলা এবং বন্ধ করার সাথে ডিল করুন।
  • onFinish আমরা যখন ফর্ম জমা দিই তখন ট্রিগার হয়৷

তারা কম্পোনেন্টের অবস্থার সাথে খেলবে, যা শুধুমাত্র মোডাল টগল সংরক্ষণ করবে (যেমন, এটি দৃশ্যমান কিনা):

state = {
  visible: false,
};

মডেলটি দেখাতে বা লুকানোর জন্য, আমাদের শুধু এই বুলিয়ানকে টগল করতে হবে:

this.setState({
  visible: true,
});

বিয়ারের API কল করতে এবং একটি নতুন বিয়ার নিবন্ধন করতে, আমাদের আবার ফেচ API ব্যবহার করতে হবে:

onFinish = (values) => {
  const url = "api/v1/beers/";
  fetch(url, {
    method: "post",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(values),
  })
    .then((data) => {
      if (data.ok) {
        this.handleCancel();

        return data.json();
      }
      throw new Error("Network error.");
    })
    .then(() => {
      this.props.reloadBeers();
    })
    .catch((err) => console.error("Error: " + err));
};

এই প্রথমবার আমরা একটি অনুরোধ কল করছি যাতে আমরা সার্ভারে ডেটা পাঠাই। এই ক্ষেত্রে, আমাদের এপিআই-কে স্পষ্টভাবে বলতে হবে যে কোন ধরনের তথ্য এগিয়ে যাচ্ছে। এই কারণেই Header অ্যাট্রিবিউট অবহিত করতে হবে।

সবকিছু ঠিকঠাক থাকলে, আমরা শুধু মোডাল বন্ধ করে টেবিলের তালিকা পুনরায় লোড করি।

এখন, কম্পোনেন্ট রেন্ডার সহ সবকিছু একসাথে দেখি:

import { Button, Form, Input, Modal, Select } from "antd";
import React from "react";

const { Option } = Select;

class AddBeerModal extends React.Component {
  formRef = React.createRef();
  state = {
    visible: false,
  };

  onFinish = (values) => {
    const url = "api/v1/beers/";
    fetch(url, {
      method: "post",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(values),
    })
      .then((data) => {
        if (data.ok) {
          this.handleCancel();

          return data.json();
        }
        throw new Error("Network error.");
      })
      .then(() => {
        this.props.reloadBeers();
      })
      .catch((err) => console.error("Error: " + err));
  };

  showModal = () => {
    this.setState({
      visible: true,
    });
  };

  handleCancel = () => {
    this.setState({
      visible: false,
    });
  };

  render() {
    return (
      <>
        <Button type="primary" onClick={this.showModal}>
          Create New +
        </Button>

        <Modal title="Add New Beer ..." visible={this.state.visible} onCancel={this.handleCancel} footer={null}>
          <Form ref={this.formRef} layout="vertical" onFinish={this.onFinish}>
            <Form.Item name="brand" label="Brand" rules={[{ required: true, message: "Please input your beer brand!" }]}>
              <Input placeholder="Input your beer brand" />
            </Form.Item>

            <Form.Item name="style" label="Style" rules={[{ required: true, message: "Please input your beer style!" }]}>
              <Input placeholder="Input your beer style" />
            </Form.Item>

            <Form.Item
              name="country"
              label="Country"
              rules={[
                {
                  required: true,
                  message: "Please input the country of the beer!",
                },
              ]}
            >
              <Select showSearch placeholder="Select your beer country" optionFilterProp="children" style={{ width: "100%" }}>
                <Option value="Finland">Finland</Option>
                <Option value="Germany">Germany</Option>
                <Option value="Netherlands">Netherlands</Option>
                <Option value="UK">UK</Option>
                <Option value="USA">USA</Option>
                <Option value="Other">Other</Option>
              </Select>
            </Form.Item>

            <Form.Item name="quantity" label="Quantity" rules={[{ required: true, message: "Please input the quantity!" }]}>
              <Input type="number" placeholder="How many beers you desire?" />
            </Form.Item>

            <Form.Item>
              <Button type="primary" htmlType="submit">
                Submit
              </Button>
            </Form.Item>
          </Form>
        </Modal>
      </>
    );
  }
}

export default AddBeerModal;

Antd allows us to specify each form’s item rules individually. If a field is required, just say so by providing a rules attribute. You can customize the message it’ll display in case the user submits the form without filling it properly:

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা Validating form inputs.

Take a look at the Select component, which translates a combo box. See how easy it is to create complex components by just providing the right attributes. For example, if you want to make your select searchable, just put the showSearch property, there and it’s done:

রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা Filtering results within a Select.

Antd will automatically filter the select options based on your input.

Styling

Sometimes, you’ll need to provide some CSS styling to components that do not provide a default (like antd’s table) or customize the ones that come built-in.

To do this, you can create as many CSS files as you want and organize them in a structure that pleases you. Rails already create an application.css file, under the app/assets/stylesheets ফোল্ডার Open it and the following content:

.site-layout-content {
  background: #fff;
  padding: 24px;
  min-height: 380px;
}

.logo {
  width: 200px;
  min-height: 31px;
  margin: 16px 24px 16px 0;
  float: left;
  background-image: url(https://www.honeybadger.io/images/navbar_logo.svg?1602785015);
  background-repeat: no-repeat;
}

.table-striped-rows th,
.table-striped-rows td {
  border-bottom: 1px solid #dedddd !important;
}

.table-striped-rows tr:nth-child(2n) td {
  background-color: #fbfbfb;
}

.table-striped-rows thead {
  background-color: #f1f1f1;
}

Those are the CSS rules to make our table stripped, for example. Feel free to add as many extra styles here as you want.

পরীক্ষা

Before heading to the tests, we need to disable the CSRF token checking that Rails automatically configures for our apps. To do so, go to the app/controllers/application_controller.rb file and change it to the following:

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end

This way, we avoid having to validate the tokens each time we perform a request.

দারুণ! Now, start your server via rails s command, access the https://localhost:3000/ address, and play around with the CRUD.

উপসংহার

As a homework task, I’d recommend that you try implementing the update functionality of the CRUD. You can adapt the edit method at the API controller to receive the updated beer info and perform the update to the database. For the view, another modal would suit very well to accommodate the edit’s form.

You can also find the source code for this tutorial here. Good studies!


  1. রেলে একটি ডকুমেন্টেশন ওয়ার্কফ্লো তৈরি করা

  2. আপনার রেল অ্যাপ পরীক্ষা করার জন্য একটি ডকার কন্টেইনার সেট আপ করুন

  3. রেলে প্রতিক্রিয়া:একটি সহজ অ্যাপ তৈরি করা

  4. একটি প্রতিক্রিয়া নেটিভ অ্যাপে ভিডিও কলিং কীভাবে যুক্ত করবেন