क्या आप कभी फेसबुक पर रहे हैं और पेज को रिफ्रेश किए बिना नोटिफिकेशन प्राप्त किया है? इस तरह की रीयल-टाइम कार्यक्षमता अधिकांश अनुप्रयोगों पर जावास्क्रिप्ट फ्रेमवर्क का उपयोग करके प्राप्त की जाती है, जैसे कि राज्य प्रबंधन के माध्यम से रिएक्ट। इनमें से अधिकांश एप्लिकेशन सिंगल-पेज एप्लिकेशन के रूप में कार्य करते हैं, क्योंकि उन्हें वास्तविक समय में डेटा अपडेट करने के लिए उपयोग के दौरान पेज रीलोडिंग की आवश्यकता नहीं होती है। लंबे समय से, रेल एप्लिकेशन इस अर्थ में स्टेटलेस रहे हैं कि पेज रीलोड आमतौर पर प्राप्त करने के लिए आवश्यक है आवेदन की वर्तमान स्थिति। उदाहरण के लिए, यदि आप एक ऐसे रेल ऐप पर थे जो थिएटर में उपलब्ध फिल्मों की एक सूची दिखाता है और एक व्यवस्थापक द्वारा एक मूवी जोड़ी जाती है, तो नई जोड़ी गई मूवी आपके डैशबोर्ड पर तब तक दिखाई नहीं देगी जब तक आप पेज को रीफ्रेश नहीं करते।
ActionCable क्यों?
एक्शनकेबल इस अंतर को पाटता है और रेल एप्लिकेशन में रीयल-टाइम अपडेट और इस गतिशील कार्यक्षमता को संभव बनाता है। यह एक संचार प्रोटोकॉल का उपयोग करता है जिसे वेबसॉकेट कहा जाता है ताकि राज्य को एप्लिकेशन में पेश किया जा सके जबकि अभी भी प्रदर्शन और स्केलेबल हो। इसके साथ, उपयोगकर्ता अपने पृष्ठों को ताज़ा किए बिना अपने डैशबोर्ड पर अद्यतन सामग्री प्राप्त कर सकते हैं।
द मैजिक ऑफ टर्बो-रेल
TurboRails में टर्बो ड्राइव, टर्बो फ्रेम और टर्बो स्ट्रीम होते हैं। जब एक टर्बो-फ़्रेम में लिपटे पृष्ठ के एक भाग से एक अनुरोध भेजा जाता है, तो HTML प्रतिक्रिया उस फ़्रेम को बदल देती है, जिससे वे एक ही आईडी रखते हैं। दूसरी ओर, टर्बो स्ट्रीम, वेब पर इन आंशिक पृष्ठ अपडेट को सक्षम करते हैं। सॉकेट कनेक्शन। एक्शनकेबल इन अपडेट को एक चैनल से प्रसारित करता है, और टर्बो स्ट्रीम इस चैनल के लिए सब्सक्राइबर बनाता है और अपडेट डिलीवर करता है। परिणामस्वरूप, मॉडल परिवर्तनों के जवाब में सीधे एसिंक्रोनस अपडेट बनाए जा सकते हैं।
हम क्या बनाना चाहते हैं
इस लेख का उद्देश्य यह दिखाना है कि कैसे टर्बो एक्शनकेबल के साथ पर्दे के पीछे काम करता है ताकि रेल 6 ऐप में रीयल-टाइम अपडेट प्रसारित और प्रदर्शित किया जा सके। इस प्रकार, हम एक चैट ऐप का निर्माण करेंगे जिसमें किसी भी उपयोगकर्ता द्वारा चैट रूम बनाया जा सकता है, और सभी उपयोगकर्ता उस कमरे में संदेश भेज सकते हैं और वास्तविक समय में अपडेट प्राप्त कर सकते हैं। हम उपयोगकर्ताओं को एक दूसरे के साथ निजी तौर पर चैट करने में भी सक्षम करेंगे। हम समूह चैट आमंत्रणों को लागू नहीं करेंगे; ये इस ब्लॉग पोस्ट के दायरे से बाहर हैं क्योंकि इसमें टर्बो और एक्शनकेबल के बजाय केवल अतिरिक्त डेटाबेस डिज़ाइन शामिल हैं। हालांकि, इस पाठ के बाद, यदि आप आगे जाना चाहते हैं तो यह केक का एक टुकड़ा होना चाहिए।
यह कैसा दिखना चाहिए, या इसमें क्या होना चाहिए?
- एक अनुक्रमणिका पृष्ठ जो सभी मौजूदा चैट रूम और उपयोगकर्ताओं को सूचीबद्ध करता है।
- जब नए उपयोगकर्ता साइन अप करते हैं या नए कमरे बनाए जाते हैं तो इस पृष्ठ को गतिशील रूप से अपडेट किया जाना चाहिए।
- नए चैट रूम बनाने के लिए एक फॉर्म मौजूद है।
- किसी भी चैट रूम में संदेश बनाने के लिए एक संदेश चैट बॉक्स।
आरंभ करने के लिए 7 आसान चरण
इस ऐप में, हम चाहते हैं कि उपयोगकर्ता केवल अपने अद्वितीय उपयोगकर्ता नाम का उपयोग करके लॉगिन करें, जो सत्रों का उपयोग करके प्राप्त किया जाता है।
1. एक नया रेल ऐप बनाएं
rails new chatapp
cd chatapp
2. एक उपयोगकर्ता मॉडल बनाएं और उसे माइग्रेट करें
rails g model User username
rails db:migrate
फिर, हम उपयोगकर्ता नाम के लिए एक अद्वितीय सत्यापन जोड़ते हैं क्योंकि हम चाहते हैं कि सभी उपयोगकर्ता नाम उनके स्वामियों के लिए अद्वितीय हों। हम अपनी उपयोगकर्ता सूची के लिए वर्तमान उपयोगकर्ता को छोड़कर सभी उपयोगकर्ताओं को लाने के लिए एक गुंजाइश भी बनाते हैं, क्योंकि हम नहीं चाहते कि कोई उपयोगकर्ता स्वयं के साथ चैट कर रहा हो :)।
#app/models/user.rb
class User < ApplicationRecord
validates_uniqueness_of :username
scope :all_except, ->(user) { where.not(id: user) }
end
3. चैट रूम मॉडल बनाएं
चैट रूम का एक नाम होता है और यह एक निजी चैट रूम (दो उपयोगकर्ताओं के बीच निजी चैट के लिए) या सार्वजनिक (सभी के लिए उपलब्ध) हो सकता है। इसे इंगित करने के लिए, हम एक is_private
. जोड़ते हैं हमारे कमरे की मेज पर कॉलम।
rails g model Room name:string is_private:boolean
इस फ़ाइल को माइग्रेट करने से पहले, हम is_private
. में एक डिफ़ॉल्ट मान जोड़ देंगे कॉलम ताकि बनाए गए सभी कमरे डिफ़ॉल्ट रूप से सार्वजनिक हों, जब तक कि अन्यथा न कहा जाए।
class CreateRooms < ActiveRecord::Migration[6.1]
def change
create_table :rooms do |t|
t.string :name
t.boolean :is_private, :default => false
t.timestamps
end
end
end
इस चरण के बाद, हम rails db:migrate
. कमांड का उपयोग करके अपनी फ़ाइल को माइग्रेट करते हैं . नाम संपत्ति के लिए विशिष्टता सत्यापन और हमारी कमरे सूची के लिए सभी सार्वजनिक कमरे लाने के लिए एक दायरा जोड़ना भी आवश्यक है।
#app/models/room.rb
class Room < ApplicationRecord
validates_uniqueness_of :name
scope :public_rooms, -> { where(is_private: false) }
end
4. शैली जोड़ें
इस ऐप में न्यूनतम स्टाइल जोड़ने के लिए, हम बूटस्ट्रैप सीडीएन को हमारी application.html.erb फ़ाइल में जोड़ देंगे
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
5. प्रमाणीकरण जोड़ें
ऐप में प्रमाणीकरण जोड़ने के लिए एक current_user
. की आवश्यकता होगी हर समय परिवर्तनशील। प्रमाणीकरण को सक्षम करने के लिए अपने ऐप में बताई गई फाइलों में निम्नलिखित कोड जोड़ें।
#app/controllers/application_controller.rb
helper_method :current_user
def current_user
if session[:user_id]
@current_user = User.find(session[:user_id])
end
end
def log_in(user)
session[:user_id] = user.id
@current_user = user
redirect_to root_path
end
def logged_in?
!current_user.nil?
end
def log_out
session.delete(:user_id)
@current_user = nil
end
#app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.find_by(username: params[:session][:username])
if user
log_in(user)
else
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_path
end
end
#app/views/sessions/new.html.erb
<%= form_for (:session) do |f| %>
<%= f.label :username, 'Enter your username' %>
<%= f.text_field :username, autocomplete: 'off' %>
<%= f.submit 'Sign in' %>
<% end %>
निम्नलिखित मार्गों को रूट्स.आरबी फ़ाइल में जोड़ें।
#routes.rb
Rails.application.routes.draw do
get '/signin', to: 'sessions#new'
post '/signin', to: 'sessions#create'
delete '/signout', to: 'sessions#destroy'
end
6. नियंत्रक बनाएं
रेल जी कंट्रोलर रूम इंडेक्स
का उपयोग करके रूम्सकंट्रोलर बनाएं और हमारी अनुक्रमणिका पद्धति में उपयोगकर्ताओं और कमरों की सूची के लिए चर जोड़ें।
class RoomsController < ApplicationController
def index
@current_user = current_user
redirect_to '/signin' unless @current_user
@rooms = Room.public_rooms
@users = User.all_except(@current_user)
end
end
7. मार्ग सेट करें
routes.rb
. में रूम, यूजर और रूट रूट जोड़ें ताकि हमारा लैंडिंग पृष्ठ वह अनुक्रमणिका पृष्ठ हो जो सभी कमरों और उपयोगकर्ताओं को सूचीबद्ध करता है, और हम अपनी पसंद के किसी भी कमरे में नेविगेट कर सकते हैं।
#routes.rb
resources :rooms
resources :users
root 'rooms#index'
दृश्यों को सेट करना
टर्बो के 'मैजिक' के लिए हमारा पहला परिचय नए जोड़े गए कमरों या नए साइन-अप उपयोगकर्ताओं की स्थिति में हमारे डैशबोर्ड पर रीयल-टाइम अपडेट का स्वागत है। इसे प्राप्त करने के लिए, सबसे पहले, हम दो आंशिक बनाते हैं:<कोड _room.html.erb प्रत्येक कमरे और _user.html.erb
. को प्रदर्शित करने के लिए प्रत्येक उपयोगकर्ता को प्रदर्शित करने के लिए। हम इस सूची को index.html.erb
. में प्रस्तुत करेंगे फ़ाइल जो रूम्सकंट्रोलर बनाए जाने के समय बनाई गई थी, क्योंकि यह हमारा लैंडिंग पृष्ठ है।
# app/views/rooms/_room.html.erb
<div> <%= link_to room.name, room %> </div>
# app/views/users/_user.html.erb
<div> <%= link_to user.username, user %> </div>
हम इन फ़ाइलों को हमारे index.html.erb
. में रेंडर करने के लिए आगे बढ़ते हैं फ़ाइल, उन्हें सीधे संदर्भित करके नहीं बल्कि संग्रह लाने वाले चरों को प्रस्तुत करके। याद रखें कि हमारे RoomsController में, वेरिएबल @users
और @रूम
पहले ही परिभाषित किया जा चुका है।
#app/views/rooms/index.html.erb
<div class="container">
<h5> Hi <%= @current_user.username %> </h5>
<h4> Users </h4>
<%= render @users %>
<h4> Rooms </h4>
<%= render @rooms %>
</div>
कंसोल में, निम्न कमांड चलाएँ:
Room.create(name: 'music')
User.create(username: 'Drake')
User.create(username: 'Elon')
rails
. का उपयोग करके अपने रेल सर्वर को चालू करें . आपको साइन इन करने के लिए प्रेरित किया जाएगा; ऊपर बनाए गए किसी भी उपयोगकर्ता के उपयोगकर्ता नाम के साथ ऐसा करें, और आपके पास अपना नया बनाया गया कमरा और वह उपयोगकर्ता होना चाहिए जिसमें आपने साइन इन नहीं किया था जैसा कि नीचे दी गई छवि में दिखाया गया है।
टर्बो का परिचय
रीयल-टाइम अपडेट प्राप्त करने के लिए, हमें टर्बो इंस्टॉल करना होगा।
bundle add turbo-rails
rails turbo:install
यदि आपके पास Redis स्थापित नहीं है, तो निम्न कमांड चलाएँ:
sudo apt install redis-server
#installs redis if you don't have it yet
redis-server
#starts the server
आयात टर्बो-रेल
application.js
. में आयात "@hotwired/turbo-rails"
. का उपयोग कर फ़ाइल
इसके बाद, हम अपने मॉडलों में विशिष्ट निर्देश जोड़ेंगे और उनसे किसी विशेष चैनल पर किसी भी नए जोड़े गए इंस्टेंस को प्रसारित करने के लिए कहेंगे। यह प्रसारण एक्शनकेबल द्वारा किया जाता है, जैसा कि हम जल्द ही देखेंगे।
#app/models/user.rb
class User < ApplicationRecord
validates_uniqueness_of :username
scope :all_except, ->(user) { where.not(id: user) }
after_create_commit { broadcast_append_to "users" }
end
यहां, हम उपयोगकर्ता मॉडल को उपयोगकर्ता के हर नए उदाहरण के बनने के बाद "उपयोगकर्ता" नामक चैनल पर प्रसारित करने के लिए कह रहे हैं।
#app/models/room.rb
class Room < ApplicationRecord
validates_uniqueness_of :name
scope :public_rooms, -> { where(is_private: false) }
after_create_commit {broadcast_append_to "rooms"}
end
यहां, हम रूम मॉडल को रूम के प्रत्येक नए इंस्टेंस के बनने के बाद "रूम" नामक चैनल पर प्रसारित करने के लिए भी कह रहे हैं।
अपना कंसोल प्रारंभ करें यदि यह पहले से प्रारंभ नहीं हुआ है, या पुनः लोड करें!
. का उपयोग करें आदेश अगर यह पहले से ही चल रहा है और चल रहा है। इनमें से किसी का भी एक नया उदाहरण बनाने के बाद, हम देखते हैं कि एक्शनकेबल निर्दिष्ट चैनल में जोड़े गए इंस्टेंस को एक टर्बो स्ट्रीम के रूप में एक टेम्पलेट के रूप में आंशिक रूप से निर्दिष्ट करके प्रसारित करता है। नए जोड़े गए कमरे के लिए, यह आंशिक _room.html.erb
. को प्रसारित करता है नए जोड़े गए उदाहरण के अनुरूप मानों के साथ, जैसा कि नीचे दिखाया गया है।
हालाँकि, समस्या यह है कि प्रसारण टेम्पलेट डैशबोर्ड पर दिखाई नहीं देता है। ऐसा इसलिए है क्योंकि हमें अपने विचार में प्रसारण के एक रिसीवर को जोड़ने की जरूरत है ताकि एक्शनकेबल द्वारा जो कुछ भी प्रसारित किया जाता है उसे प्राप्त किया जा सके और जोड़ा जा सके। हम एक turbo_stream_from
. जोड़कर ऐसा करते हैं टैग, उस चैनल को निर्दिष्ट करना जिससे हम प्रसारण प्राप्त करने की आशा करते हैं। जैसा कि ऊपर की छवि में देखा गया है, प्रसारित स्ट्रीम में एक लक्ष्य विशेषता होती है, और यह उस कंटेनर की आईडी निर्दिष्ट करती है जिसमें स्ट्रीम को जोड़ा जाएगा। इसका मतलब यह है कि ब्रॉडकास्ट टेम्प्लेट "रूम" की आईडी वाले कंटेनर की खोज करेगा, जिसमें जोड़ा जाना है; इसलिए, हम अपनी अनुक्रमणिका फ़ाइल में उक्त आईडी के साथ एक div शामिल करते हैं। इसे प्राप्त करने के लिए, हमारे index.html.erb
में फ़ाइल, हम <%=रेंडर @users%>
. को प्रतिस्थापित करते हैं साथ:
<%= turbo_stream_from "users" %>
<div id="users">
<%= render @users %>
</div>
और <%=रेंडर @rooms %>
के साथ
<%= turbo_stream_from "rooms" %>
<div id="rooms">
<%= render @rooms %>
</div>
इस समय, हम टर्बो के जादू का अनुभव कर सकते हैं। हम अपने पेज को रीफ्रेश कर सकते हैं और हमारे कंसोल से नए उपयोगकर्ता और कमरे जोड़ना शुरू कर सकते हैं और वास्तविक समय में उन्हें हमारे पेज से जोड़ सकते हैं। यिप्पी!!!
कंसोल से नए कमरे बनाने से थक गए हैं? आइए एक ऐसा फ़ॉर्म जोड़ें जो उपयोगकर्ताओं को नए कमरे बनाने में सक्षम बनाता है।
#app/views/layouts/_new_room_form.html.erb
<%= form_with(model: @room, remote: true, class: "d-flex" ) do |f| %>
<%= f.text_field :name, class: "form-control", autocomplete: 'off' %>
<%= f.submit data: { disable_with: false } %>
<% end %>
उपरोक्त फॉर्म में, @room
उपयोग किया जाता है, लेकिन इसे अभी तक हमारे नियंत्रक में परिभाषित नहीं किया गया है; इस प्रकार, हम इसे परिभाषित करते हैं और इसे अपने RoomsController की अनुक्रमणिका पद्धति में जोड़ते हैं।
@room = Room.new
जब क्रिएट बटन पर क्लिक किया जाता है, तो यह रूम्सकंट्रोलर में एक क्रिएट मेथड पर रूट हो जाएगा, जो इस समय मौजूद नहीं है; इसलिए, हमें इसे जोड़ना होगा।
#app/controllers/rooms_controller.rb
def create
@room = Room.create(name: params["room"]["name"])
end
हम इस फॉर्म को अपनी अनुक्रमणिका फ़ाइल में इसके आंशिक रूप से प्रस्तुत करके जोड़ सकते हैं:
<%= render partial: "layouts/new_room_form" %>
साथ ही, हम कुछ बूटस्ट्रैप क्लासेस जोड़ सकते हैं ताकि पेज को कमरे और उपयोगकर्ताओं की सूची के लिए एक भाग में विभाजित किया जा सके और दूसरा चैट के लिए।
<div class="row">
<div class="col-md-2">
<h5> Hi <%= @current_user.username %> </h5>
<h4> Users </h4>
<div>
<%= turbo_stream_from "users" %>
<div id="users">
<%= render @users %>
</div>
</div>
<h4> Rooms </h4>
<%= render partial: "layouts/new_room_form" %>
<div>
<%= turbo_stream_from "rooms" %>
<div id="rooms">
<%= render @rooms %>
</div>
</div>
</div>
<div class="col-md-10 bg-dark">
The chat box stays here
</div>
</div>
जोड़े गए कमरों की इमेज रीयल-टाइम में अपडेट की गई
अब, नए कमरे बनाने पर, हम देख सकते हैं कि ये कमरे बनाए गए हैं, और पृष्ठ रीयल-टाइम में अपडेट किया गया है। आपने शायद यह भी देखा होगा कि हर सबमिशन के बाद फॉर्म क्लियर नहीं होता है; हम बाद में प्रोत्साहन का उपयोग करके इस समस्या का समाधान करेंगे।
ग्रुप चैट्स
समूह चैट के लिए, हमें अलग-अलग कमरों में जाने में सक्षम होना चाहिए, लेकिन एक ही पृष्ठ पर बने रहना चाहिए। हम अपने RoomsController शो मेथड में सभी इंडेक्स पेज-आवश्यक वेरिएबल्स को जोड़कर और इंडेक्स पेज को स्टिल रेंडर करके ऐसा करते हैं।
#app/controllers/rooms_controller.rb
def show
@current_user = current_user
@single_room = Room.find(params[:id])
@rooms = Room.public_rooms
@users = User.all_except(@current_user)
@room = Room.new
render "index"
end
@single_room
. नामक एक अतिरिक्त चर शो विधि में जोड़ा गया है। यह हमें उस विशेष कमरे को देता है जिस पर रूट किया जा रहा है; इसलिए, हम अपने इंडेक्स पेज पर एक सशर्त विवरण जोड़ सकते हैं जो उस कमरे का नाम दिखाता है जिसे हमने कमरे के नाम पर क्लिक करने पर नेविगेट किया है। इसे वर्ग नाम col-md-10
. के साथ div में जोड़ा जाता है , जैसा कि नीचे दिखाया गया है।
<div class="col-md-10 bg-dark text-light">
<% if @single_room %>
<h4 class="text-center"> <%= @single_room.name %> </h4>
<% end %>
</div>
कई कमरों में चलती हुई छवि
अब हम कुछ और रसीले सामान, मैसेजिंग की ओर बढ़ेंगे। हमें अपने चैट सेक्शन को 100vh की ऊंचाई देनी होगी ताकि यह पेज को भर सके और मैसेज क्रिएशन के लिए इसमें चैट बॉक्स शामिल कर सके। चैटबॉक्स को एक संदेश मॉडल की आवश्यकता होगी। इस मॉडल में एक उपयोगकर्ता संदर्भ और एक कमरे का संदर्भ होगा, क्योंकि एक संदेश एक निर्माता और उस कमरे के बिना मौजूद नहीं हो सकता जिसके लिए इसका मतलब था।
rails g model Message user:references room:references content:text
rails db:migrate
हमें उपयोगकर्ता और कमरे के मॉडल में निम्न पंक्ति जोड़कर इस जुड़ाव की पहचान करने की भी आवश्यकता है।
has_many :messages
आइए संदेश निर्माण के लिए हमारे पेज में एक फॉर्म जोड़ें और उसमें स्टाइल जोड़ें:
#app/views/layouts/_new_message_form.html.erb
<div class="form-group msg-form">
<%= form_with(model: [@single_room ,@message], remote: true, class: "d-flex" ) do |f| %>
<%= f.text_field :content, id: 'chat-text', class: "form-control msg-content", autocomplete: 'off' %>
<%= f.submit data: { disable_with: false }, class: "btn btn-primary" %>
<% end %>
</div>
#app/assets/stylesheets/rooms.scss
.msg-form {
position: fixed;
bottom: 0;
width: 90%
}
.col-md-10 {
height: 100vh;
overflow: scroll;
}
.msg-content {
width: 80%;
margin-right: 5px;
}
इस फ़ॉर्म में एक @message
. शामिल है चर; इसलिए, हमें इसे अपने नियंत्रक में परिभाषित करने की आवश्यकता है। हम इसे अपने RoomsController के शो मेथड में जोड़ते हैं।
@message = Message.new
हमारे routes.rb
. में फ़ाइल में, हम संदेश संसाधन को रूम रिसोर्स में जोड़ते हैं, क्योंकि यह पैराम्स से जुड़ता है, उस कमरे की आईडी जिससे संदेश बनाया जा रहा है।
resources :rooms do
resources :messages
end
जब भी कोई नया संदेश बनाया जाता है, तो हम चाहते हैं कि इसे उस कमरे में प्रसारित किया जाए जिसमें इसे बनाया गया था। ऐसा करने के लिए, हमें एक संदेश आंशिक चाहिए जो संदेश को प्रस्तुत करता है। जैसा कि यही प्रसारित किया जाएगा, हमें एक turbo_stream
. की भी आवश्यकता है जो उस विशेष कमरे के लिए प्रसारित संदेश प्राप्त करता है और एक div जो इन संदेशों को जोड़ने के लिए कंटेनर के रूप में कार्य करेगा। यह न भूलें कि इस कंटेनर की आईडी प्रसारण के लक्ष्य के समान होनी चाहिए।
हम इसे अपने संदेश मॉडल में जोड़ते हैं:
#app/models/message.rb
after_create_commit { broadcast_append_to self.room }
इस तरह, यह उस विशेष कमरे में प्रसारित होता है जिसमें इसे बनाया गया था।
हम अपनी अनुक्रमणिका फ़ाइल में स्ट्रीम, संदेश कंटेनर और संदेश प्रपत्र भी जोड़ते हैं:
#within the @single_room condition in app/views/rooms/index.html.erb
<%= turbo_stream_from @single_room %>
<div id="messages">
</div>
<%= render partial: 'layouts/new_message_form' >
हम उस संदेश को आंशिक बनाते हैं जिसे प्रसारित किया जाएगा, और इसमें, हम प्रेषक का उपयोगकर्ता नाम तभी दिखाते हैं जब कमरा सार्वजनिक हो।
#app/views/messages/_message.html.erb
<div>
<% unless message.room.is_private %>
<h6 class="name"> <%= message.user.username %> </h6>
<% end %>
<%= message.content %>
</div>
कंसोल से, यदि हम कोई संदेश बनाते हैं, तो हम देख सकते हैं कि उसे निर्दिष्ट टेम्पलेट का उपयोग करके उसके कमरे में प्रसारित किया जाता है।
डैशबोर्ड से संदेश निर्माण को सक्षम करने के लिए, हमें MessagesController में बनाने की विधि को जोड़ना होगा।
#app/controllers/messages_controller.rb
class MessagesController < ApplicationController
def create
@current_user = current_user
@message = @current_user.messages.create(content: msg_params[:content], room_id: params[:room_id])
end
private
def msg_params
params.require(:message).permit(:content)
end
end
हमें यही मिलता है:
जैसा कि हम ऊपर दिए गए वीडियो में देख सकते हैं, संदेश संलग्न हैं, लेकिन यदि हम दूसरे चैट रूम में जाते हैं, तो ऐसा लगता है कि जब हम वापस लौटते हैं तो हम पिछले वाले संदेशों को खो देते हैं। ऐसा इसलिए है क्योंकि हम उन संदेशों को नहीं ला रहे हैं जो प्रदर्शन के लिए एक कमरे से संबंधित हैं। ऐसा करने के लिए, रूम्सकंट्रोलर शो विधि में, हम एक वेरिएबल जोड़ते हैं जो एक कमरे से संबंधित सभी संदेशों को प्राप्त करता है, और इंडेक्स पेज पर, हम प्राप्त किए गए संदेशों को प्रस्तुत करते हैं। हम यह भी देख सकते हैं कि संदेश भेजे जाने के बाद संदेश प्रपत्र साफ़ नहीं होता है; इसे स्टिमुलस के साथ नियंत्रित किया जाएगा।
#in the show method of app/controllers/rooms_controller.rb
@messages = @single_room.messages
#within the div with id of 'messages'
<%= render @messages %>
अब, प्रत्येक कमरे के प्रवेश द्वार पर उसके संदेश लोड होंगे।
हमें वर्तमान उपयोगकर्ता के संदेशों को दाईं ओर और अन्य को बाईं ओर संरेखित करके इस रूप को और अधिक प्रस्तुत करने योग्य बनाने की आवश्यकता है। इसे प्राप्त करने का सबसे सीधा तरीका यह होगा कि message.user ==current_user
की स्थिति के आधार पर कक्षाएं आवंटित की जाएं। , लेकिन स्थानीय चर स्ट्रीम के लिए उपलब्ध नहीं हैं; इसलिए, प्रसारित संदेश के लिए कोई current_user
नहीं होगा ।हम क्या कर सकते हैं? हम संदेश भेजने वाले की आईडी के आधार पर संदेश कंटेनर को एक वर्ग असाइन कर सकते हैं और फिर current_user
का लाभ उठा सकते हैं हमारे application.html.erb
. में शैली जोड़ने के लिए सहायक विधि फ़ाइल। इस प्रकार, यदि वर्तमान उपयोगकर्ता की आईडी 2 है, तो application.html.erb
में शैली टैग में वर्ग होगा .msg-2
, जो हमारे संदेश आंशिक में वर्ग के अनुरूप होगा जब संदेश भेजने वाला वर्तमान उपयोगकर्ता है।
#app/views/messages/_message.html.erb
<div class="cont-<%= message.user.id %>">
<div class="message-box msg-<%= message.user.id %> " >
<% unless message.room.is_private %>
<h6 class="name"> <%= message.user.username %> </h6>
<% end %>
<%= message.content %>
</div>
</div>
हम संदेश-बॉक्स
add जोड़ते हैं स्टाइलिंग:
#app/assets/stylesheets/rooms.scss
.message-box {
width: fit-content;
max-width: 40%;
padding: 5px;
border-radius: 10px;
margin-bottom: 10px;
background-color: #555555 ;
padding: 10px
}
हमारे application.html.erb
. के हेड टैग में फ़ाइल।
#app/views/layouts/application.html.erb
<style>
<%= ".msg-#{current_user&.id}" %> {
background-color: #007bff !important;
padding: 10px;
}
<%= ".cont-#{current_user&.id}" %> {
display: flex;
justify-content: flex-end
}
</style>
हम !महत्वपूर्ण
जोड़ते हैं पृष्ठभूमि-रंग
. को टैग करें क्योंकि हम चाहते हैं कि वर्तमान उपयोगकर्ता के लिए पृष्ठभूमि का रंग ओवरराइड हो जाए।
हमारी चैट तब इस तरह दिखती है:
निजी चैट
प्राइवेट चैट के लिए जरूरी ज्यादातर काम ग्रुप चैट सेटअप के दौरान ही किए जाते थे। अब हमें बस इतना करना है:
- किसी विशेष उपयोगकर्ता को रूट करते समय निजी चैट के लिए एक निजी कमरा बनाएं यदि ऐसा कोई कमरा मौजूद नहीं है।
- ऐसे कमरों के लिए प्रतिभागी बनाएं ताकि कोई घुसपैठिया कंसोल से भी ऐसे कमरों में संदेश न भेज सके।
- नए बनाए गए निजी कक्षों को कक्ष सूची में प्रसारित होने से रोकें.
- एक निजी चैट होने पर कमरे के नाम के बजाय उपयोगकर्ता का नाम प्रदर्शित करें।
किसी विशेष उपयोगकर्ता को रूट करने में, वर्तमान उपयोगकर्ता यह संकेत दे रहा है कि वे उस उपयोगकर्ता के साथ निजी तौर पर चैट करना चाहते हैं। इसलिए, हमारे UsersController
. में , हम जांचते हैं कि क्या इन दोनों के बीच ऐसा कोई निजी कमरा मौजूद है। अगर ऐसा होता है, तो यह हमारा @single_room
बन जाता है चर; अन्यथा, हम इसे बनाएंगे। हम प्रत्येक निजी चैट रूम के लिए एक विशेष कमरे का नाम बनाएंगे ताकि जरूरत पड़ने पर हम इसका संदर्भ दे सकें। हमें एक ही पेज पर बने रहने के लिए शो मेथड में इंडेक्स पेज के लिए आवश्यक सभी वेरिएबल्स को भी शामिल करना होगा।
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
@current_user = current_user
@rooms = Room.public_rooms
@users = User.all_except(@current_user)
@room = Room.new
@message = Message.new
@room_name = get_name(@user, @current_user)
@single_room = Room.where(name: @room_name).first || Room.create_private_room([@user, @current_user], @room_name)
@messages = @single_room.messages
render "rooms/index"
end
private
def get_name(user1, user2)
users = [user1, user2].sort
"private_#{users[0].id}_#{users[1].id}"
end
end
जैसा कि हम ऊपर देख सकते हैं, हमें एक create_private_room
. जोड़ना होगा हमारे रूम मॉडल के लिए विधि, जो एक निजी कमरा और उसके प्रतिभागियों का निर्माण करेगी। यह हमें प्रतिभागी
. नामक एक नया मॉडल बनाने के लिए प्रेरित करता है , जो एक उपयोगकर्ता और उस निजी कमरे को इंगित करेगा जिससे वह संबंधित है।
rails g model Participant user:references room:references
rails db:migrate
हमारे रूम मॉडल में, हम create_private_room
. जोड़ते हैं विधि और हमारे after_create
change को बदलें केवल कमरे का नाम प्रसारित करने के लिए कॉल करें यदि यह एक निजी कमरा नहीं है।
#app/models/room.rb
has_many :participants, dependent: :destroy
after_create_commit { broadcast_if_public }
def broadcast_if_public
broadcast_append_to "rooms" unless self.is_private
end
def self.create_private_room(users, room_name)
single_room = Room.create(name: room_name, is_private: true)
users.each do |user|
Participant.create(user_id: user.id, room_id: single_room.id )
end
single_room
end
अन्य उपयोगकर्ताओं को एक निजी कमरे में संदेश भेजने से रोकने के लिए, जब वे प्रतिभागी नहीं होते हैं, हम एक before_create
जोड़ते हैं संदेश मॉडल की जाँच करें। इस प्रकार, निजी कमरों के लिए, इस बात की पुष्टि की जाती है कि संदेश भेजने वाला वास्तव में इस तरह के संदेश के निर्माण से पहले उस निजी बातचीत का भागीदार है। हमें ध्यान देना चाहिए कि डैशबोर्ड से, निजी कमरे में संदेश भेजना असंभव है यदि आप प्रतिभागी नहीं हैं क्योंकि आपको केवल उपयोगकर्ता नाम पर क्लिक करने की आवश्यकता है और फिर कमरा दोनों उपयोगकर्ताओं के लिए बनाया गया है। यह चेक केवल अतिरिक्त सुरक्षा के लिए है, क्योंकि एक संदेश गैर-प्रतिभागी द्वारा कंसोल से बनाया जा सकता है।
#app/models/message.rb
before_create :confirm_participant
def confirm_participant
if self.room.is_private
is_participant = Participant.where(user_id: self.user.id, room_id: self.room.id).first
throw :abort unless is_participant
end
end
निजी चैट के दौरान कमरे के नाम के बजाय उपयोगकर्ता का उपयोगकर्ता नाम प्रदर्शित करने के लिए, हम अपने अनुक्रमणिका पृष्ठ पर इंगित करते हैं कि यदि @user
चर मौजूद है, उपयोगकर्ता का उपयोगकर्ता नाम दिखाया जाना चाहिए। ध्यान दें कि यह चर केवल UserController शो विधि में मौजूद है। यह h4 टैग की ओर ले जाता है जो कमरे का नाम इस में बदलता हुआ दिखा रहा है:
<h4 class="text-center"> <%= @user&.username || @single_room.name %> </h4>
अब, जब हम किसी उपयोगकर्ता पर नेविगेट करते हैं, तो हम कमरे के नाम के बजाय उपयोगकर्ता का उपयोगकर्ता नाम देखते हैं, और हम संदेश भेज और प्राप्त कर सकते हैं। आइए हमारे होम पेज पर साइन-आउट लिंक जोड़ना न भूलें।
<%= link_to 'Sign Out', signout_path, :method => :delete %>
जैसा कि आप नीचे देख सकते हैं, निजी चैट के लिए, प्रेषक का उपयोगकर्ता नाम नहीं दिखाया गया है। हम अपने संदेशों को उनकी स्थिति से पहचानने में सक्षम हैं।
उत्तेजना
हम फ़ॉर्म को साफ़ करने के लिए प्रोत्साहन का उपयोग करेंगे क्योंकि एक पूर्ण-पृष्ठ पुन:प्रस्तुत नहीं होता है, और नए मॉडल इंस्टेंस निर्माण पर फ़ॉर्म साफ़ नहीं होते हैं।
bundle add stimulus-rails
rails stimulus:install
यह निम्न फ़ाइलें जोड़ता है, जैसा कि नीचे दी गई छवि में देखा गया है।
हम एक reset_form_controller.js
बनाते हैं हमारे प्रपत्रों को रीसेट करने के लिए फ़ाइल करें और इसमें निम्न फ़ंक्शन जोड़ें।
//app/javascript/controllers/reset_form_controller.js
import { Controller } from "stimulus"
export default class extends Controller {
reset() {
this.element.reset()
}
}
फिर, हम अपने प्रपत्रों में एक डेटा विशेषता जोड़ते हैं, जो नियंत्रक और क्रिया को दर्शाता है।
data: { controller: "reset-form", action: "turbo:submit-end->reset-form#reset" }
उदाहरण के लिए, form_with
हमारे संदेश प्रपत्र का टैग निम्न में बदल जाता है:
<%= form_with(model: [@single_room ,@message], remote: true, class: "d-flex",
data: { controller: "reset-form", action: "turbo:submit-end->reset-form#reset" }) do |f| %>
अंत में, यह वह सब है जिसकी आवश्यकता है; एक नया संदेश या कमरा बनने के बाद हमारे फ़ॉर्म साफ़ हो जाते हैं। हमें यह भी ध्यान रखना चाहिए कि प्रोत्साहन क्रिया "ajax:success->reset-form#reset"
ajax:success
. होने पर फ़ॉर्म को भी साफ़ कर सकता है घटना होती है।
निष्कर्ष
इस ऐप में, हमने टर्बो स्ट्रीम की संलग्न कार्रवाई पर ध्यान केंद्रित किया है, लेकिन टर्बो स्ट्रीम में यह सब कुछ नहीं है। वास्तव में, टर्बो स्ट्रीम में पांच क्रियाएं होती हैं:एपेंड, प्रीपेन्ड, रिप्लेस, अपडेट और रिमूव। वास्तविक समय में चैट संदेशों को हटाने और अपडेट करने को लागू करने के लिए, ये क्रियाएं काम आएंगी, और टर्बो फ्रेम के कुछ ज्ञान और उनके काम करने के तरीके की आवश्यकता हो सकती है। यह भी ध्यान रखना महत्वपूर्ण है कि कुछ के लिए वेबसॉकेट अपडेट पर निर्भर अनुप्रयोगों के लिए सुविधाओं, खराब कनेक्शन पर, या यदि सर्वर समस्याएँ हैं, तो आपका वेबसॉकेट डिस्कनेक्ट हो सकता है। इसलिए यह सलाह दी जाती है कि टर्बो स्ट्रीम का उपयोग केवल तभी करें जब यह अत्यंत महत्वपूर्ण हो।