কম্পিউটার টিউটোরিয়াল

Kredis দিয়ে Rails-এ Ephemeral UI State সহজে স্টোর করুন

Kredis (Keyed Redis) হল Rails ডেভেলপারের টুলকিটে একটি সাম্প্রতিক যোগ। এটি Redis-এ স্ট্রাকচার্ড ডেটা স্টোর ও অ্যাক্সেস করা সহজ করে তোলে।

এই টু-পার্ট সিরিজের প্রথম পার্টে আমরা Kredis কীভাবে কাজ করে সেটা বুঝব, তারপর একটি বেসপোক Redis কী ব্যবহার করে ephemeral UI state স্টোর করার উদাহরণ দেখব।

Rails-এ Kredis পরিচিতি

Kredis একটি Railtie যা তিনভাবে ব্যবহার সহজ করে:

  • Ruby-esque API: কালেকশন টাইপ যেমন Kredis.list বা Kredis.set নেটিভ Ruby টাইপের API অনুকরণ করে।
  • Typings: কালেকশনের জন্য খুব উপযোগী, Kredis এলিমেন্টগুলো স্ট্যান্ডার্ড ডেটা টাইপে (যেমন datetime, json) টাইপ কাস্ট করতে পারে।
  • ActiveRecord DSL: সম্ভবত লাইব্রেরির সবচেয়ে বড় সুবিধা — যেকোনো Redis ডেটা স্ট্রাকচারকে একটি স্পেসিফিক মডেল ইনস্ট্যান্স-এর সাথে সহজে কানেক্ট করতে দেয়।

README-র একটি উদাহরণ:

class User < ApplicationRecord
  kredis_list :recently_viewed_product_ids
end

user.recently_viewed_product_ids.append(product.id)
user.recently_viewed_product_ids.elements # => [1, 2, 3]

Kredis-এর বড় সুবিধা: একটি নির্দিষ্ট রেকর্ডের সাথে জড়িত ephemeral ইনফরমেশন স্টোর করা যা সেশন থেকে স্বতন্ত্র। সাধারণত Rails-এ ডেটা পারসিস্ট করার দুটি সাধারণ অপশন:

  • ActiveRecord: কলাম যোগ বা ডেটা মডেল প্যাচ করতে হয়, মাইগ্রেশন লাগে।
  • Session: ডিফল্ট key/value store, সেটআপ লাগে না। কিন্তু লগইন/লগআউট সাইকেলে ডেটা সার্ভাইভ করে না।

Kredis তৃতীয় অপশন আনে। কম সেটআপ (মডেলে DSL ইনভোক ছাড়া), কিন্তু আপনার Redis ইনস্ট্যান্স ডাউন না হওয়া পর্যন্ত ডেটা সেশন এবং ডিভাইস জুড়ে স্টোর থাকে। তাই Kredis-এর ভালো ইউজ কেস: আনক্রিটিক্যাল ইনফরমেশন যা ডিভাইস বর্ডার জুড়ে শেয়ার করতে চান (যেমন ওয়েব অ্যাপ এবং কম্পানিয়ন মোবাইল অ্যাপ)।

Case Study: Kredis দিয়ে Collapsed/Expanded UI State পারসিস্ট ও রিস্টোর

Kredis-এর জন্য ভালো ইউজ কেস: UI state পারসিস্ট করা, যেমন:

  • সাইডবার ওপেন/ক্লোজড স্টেট
  • ট্রি ভিউ ওপেন/ক্লোজড
  • অকর্ডিয়ন collapsed/expanded স্টেট
  • কাস্টম ড্যাশবোর্ড লেআউট
  • ডেটা টেবিলে কত লাইন দেখাবে

উদাহরণস্বরূপ, আমরা <details> এলিমেন্টের collapsed/expanded স্টেট ম্যানেজ করব।

ফ্রেশ Rails অ্যাপ ও Kredis সেটআপ

$ rails new store_app
$ bundle add kredis
$ rails g kredis:install

নোট: এটি config/redis/shared.yml-এ Redis কনফিগারেশন ফাইল তৈরি করবে।

লোকাল Redis ইনস্ট্যান্স রানিং আছে ধরে নিচ্ছি। macOS-এ Homebrew-এ: brew install redis && brew services start redis।

User Authentication

UI state ইনফরমেশন স্টোর করার জন্য User মডেল ব্যবহার করব। Devise-এর আউট-অফ-দ-বক্স ব্যবহার করি:

$ bundle add devise
$ rails g devise:install
$ rails g devise User
$ rails db:migrate
$ rails c -e "User.create!(email: 'test@example.com', password: 'password')"

আমাদের এক্সাম্পল অ্যাপ: একটি অনলাইন স্টোর

কমপ্লেক্স ট্রি স্ট্রাকচারের স্টেট পারসিস্ট করতে Kredis কীভাবে সাহায্য করে তা দেখাতে আমরা অনুমান করি আমরা একটি অনলাইন ডিপার্টমেন্ট স্টোর চালাচ্ছি। Department এবং Product মডেল স্কাফফোল্ড করব। Department-এ self-join ব্যবহার করে টু-লেভেল নেস্টেড স্ট্রাকচার বানাব।

$ rails g scaffold Department name:string parent_id:integer
$ rails g scaffold Product name:string department:references
$ rails db:migrate

Null parents পারমিট করুন ট্রি রুটের জন্য। Department এবং Product মডেল ডিফাইন করুন। Faker দিয়ে সিড ডেটা জেনারেট করুন।

Storefront স্কাফফোল্ড

সিম্পল HomeController স্টোরফ্রন্ট হিসেবে কাজ করবে। ডিপার্টমেন্টের চিল্ড্রেন সেলফ-জয়িন করি শুধু সাবডিপার্টমেন্ট থাকা রুট ডিপার্টমেন্টগুলো পাওয়ার জন্য।

Index ভিউতে নেস্টেড ট্রি ভিউ সেটআপ করি দুটি লেভেল <details> এলিমেন্ট দিয়ে:

<%= render partial: 'department', collection: @departments %>


<details>
  <summary><%= department.name %></summary>
  <%= render partial: 'department', collection: department.children %>
  <%= render partial: 'product', collection: department.products %>
</details>

এখন ডিপার্টমেন্টের ট্রি ভিউ আছে যা ওপেন/ক্লোজ করে এক্সপ্লোর করা যায়:

Kredis দিয়ে Rails-এ Ephemeral UI State সহজে স্টোর করুন

আমরা চাই ইনডিভিজুয়াল ক্যাটাগরির disclosure state পারসিস্ট করা।

Kredis-এ UI State পারসিস্ট করুন

  1. User মডেলে kredis_set যোগ করুন: open_department_ids। Set ব্যবহার করা হয়েছে কারণ ডুপ্লিকেট অ্যালো করে না, সেজন্য ডিপার্টমেন্ট সফলি অ্যাড/রিমুভ করা যায়।
  2. UIStateController তৈরি করুন: department_id এবং open স্টেট প্যারামিটার রিসিভ করবে। করেন্ট লগড-ইন ইউজারের kredis_set-এ ডিপার্টমেন্ট অ্যাড বা রিমুভ করবে।
  3. Stimulus Controller তৈরি করুন: <details> এলিমেন্টের toggle ইভেন্ট লিসেন করবে এবং পেলোড পাঠাবে।

User মডেলে Kredis ডেটা স্ট্রাকচার যোগ:

class User < ApplicationRecord
  kredis_set :open_department_ids
end

UIStateController জেনারেট করুন (route patch এন্ডপয়েন্ট হিসেবে কনফিগার করুন):

$ rails g controller UIState update

Controller-এ Kredis API ব্যবহার:

class UIStateController < ApplicationController
  def update
    department_id = params[:department_id].to_i
    open = params[:open] == 'true'

    if open
      current_user.open_department_ids << department_id
    else
      current_user.open_department_ids.remove(department_id)
    end

    head :ok
  end
end

Kredis API Ruby ডেভেলপারের এক্সপেক্টেশন অনুযায়ী কনফর্ম করতে চায় — set-এ অ্যাড করতে <<, ডিলিট করতে remove।

ক্লায়েন্ট-সাইড কোড লিখুন @rails/request.js ব্যবহার করে (pin করুন):

# app/javascript/controllers/ui_state_controller.js
import { Controller } from "@hotwired/stimulus"
import { patch } from "@rails/request.js"

export default class extends Controller {
  toggle(event) {
    const departmentId = this.element.dataset.departmentId
    const open = this.element.open

    const formData = new FormData()
    formData.append("department_id", departmentId)
    formData.append("open", open)

    patch("/ui_state", { body: formData })
  }
}

ভিউতে Stimulus কন্ট্রোলার আট্যাচ করুন এবং toggle ইভেন্ট লিসেন করুন:

<details data-controller="ui-state" data-action="toggle->ui-state#toggle" data-department-id="<%= department.id %>">
  <summary><%= department.name %></summary>
  ...
</details>

DOM ম্যানুয়ালি রিহাইড্রেট করুন

শেষ কম্পোনেন্ট: ইউজার পেজ রিফ্রেশ করলে DOM কাঙ্খিত স্টেটে রিহাইড্রেট করা। <details> নোডে open অ্যাট্রিবিউট যোগ করুন (যদি ডিপার্টমেন্ট ID Kredis set-এ থাকে):

<details data-controller="ui-state" data-action="toggle->ui-state#toggle" 
         data-department-id="<%= department.id %>"
         <%= department.open? ? 'open' : '' %>>
  <summary><%= department.name %></summary>
  ...
</details>

ফলাফল: ইনডিভিজুয়াল ট্রি নোডের ওপেন/ক্লোজড স্টেট ২ লেভেল পর্যন্ত প্রিজার্ভ হয়।

পরবর্তী পর্ব: UI State-এর জন্য Generalized User-local Container

প্রথম পার্টে Kredis পরিচিতি এবং collapsed/expanded UI state পারসিস্ট ও রিস্টোর দেখলাম। অনলাইন ডিপার্টমেন্ট স্টোর উদাহরণ দিয়ে কমপ্লেক্স ট্রি স্ট্রাকচারের স্টেট Kredis কীভাবে পারসিস্ট করে সেটা হাইলাইট করলাম, এবং শেষে ম্যানুয়ালি DOM রিহাইড্রেট করলাম।

কিন্তু এর মানে আমাকে অনেক Kredis কী আবিষ্কার করতে হবে। পরের পর্বে দেখব কীভাবে একটি generalized user-local container দিয়ে এটা সমাধান করা যায়।

তখন পর্যন্ত Happy coding!

P.S. Ruby Magic পোস্টগুলি প্রকাশ होते সাথে সাথে পেতে আমাদের Ruby Magic নিউজলেটার সাবস্ক্রাইব করুন!

  1. HTML <area> rel অ্যাট্রিবিউট

  2. HTML DOM Input DatetimeLocal max প্রোপার্টি

  3. বাইনারি ম্যাট্রিক্স কে শূন্য ম্যাট্রিক্সে রূপান্তরের অপারেশন গণনা (C++ প্রোগ্রাম)

  4. এন্ড্রয়েড ডিভাইসে ফোন কল শনাক্ত করার পদ্ধতি