यदि आप पेज परिवर्तनों और फॉर्म सबमिशन को तेज़ करने और जटिल पेज को बिना कोई JavaScript कोड लिखे घटकों में विभाजित करने का तरीका ढूंढ रहे हैं, तो यह पोस्ट आपको Hotwire के साथ Rails को अगले स्तर पर ले जाने में मदद करेगी। यह लेख आपको सर्वर-साइड रेंडरिंग के लिए एक टूल का उपयोग करना सिखाएगा।
Hotwire क्या है?
Hotwire HTML को JSON के बजाय वायर पर भेजकर JavaScript लिखे बिना आधुनिक वेब एप्लिकेशन बनाने का एक तरीका प्रदान करता है, जो पेज को तेज़ी से लोड करता है। यह सर्वर-साइड पर रेंडरिंग को बनाए रखता है और एक सरल और अधिक उत्पादक विकास अनुभव की अनुमति देता है, जैसा कि Rails ने हमेशा अपनी तकनीकों में शामिल किया है, बिना पारंपरिक सिंगल-पेज एप्लिकेशन (SPA) से जुड़ी गति या प्रतिक्रियाशीलता का त्याग किए।
Hotwire का मूल Turbo जेम है। यह पूरक तकनीकों का एक सेट है जो पेज नेविगेशन और फॉर्म सबमिशन को तेज करता है, जटिल पेज को घटकों में विभाजित करता है, और WebSocket (जिसमें ActionCable, चैनल्स, और स्ट्रीमिंग डेटा शामिल हैं) के माध्यम से पेज के आंशिक अपडेट्स को प्रसारित करता है।
आपको इसका उपयोग क्यों करना चाहिए?
यदि आप JavaScript से जूझते हैं और पेजों के बीच नेविगेट करने की तेज़ भावना के माध्यम से बेहतर उपयोगकर्ता अनुभव का लाभ उठाना चाहते हैं, तो Hotwire आपके लिए एक विकल्प है।
Hotwire कैसे काम करता है? Hotwire सर्वर-साइड रेंडरिंग (SSR) का उपयोग करके SPAs से जुड़ी कुछ समस्याओं को हल करता है जबकि उनके मुख्य लाभों को बनाए रखता है। SSR रेंडरिंग प्रक्रिया को उलट देता है, SPA रेंडरिंग प्रयास के कुछ हिस्से को सर्वर पर लाता है, पारंपरिक लोडिंग के समान। SSR उपयोगकर्ताओं को एप्लिकेशन के अधिक कुशल लोडिंग के साथ प्रदान कर सकता है क्योंकि कुछ रेंडरिंग सर्वर पर की जाती है। प्रदर्शन में सुधार की संभावना के अलावा, यह इंडेक्सिंग जैसी कुछ SEO समस्याओं से निपटने में मदद करता है।
क्या यह उपयोग करने में सरल है?
इसका उपयोग करना बहुत सरल है; आपको बस एक Rails प्रोजेक्ट का डिफ़ॉल्ट पैकेज चाहिए (Ruby, RoR, ActionCable, और WebSocket), एक Turbo जेम जो सभी JS निर्भरताओं को डाउनलोड करता है, और WebSocket ब्राउज़ करते समय कुछ अस्थायी डेटा स्टोर करने के लिए Redis।
आपको सिंगल-पेज वेब एप्लिकेशन की गति प्राप्त करने के लिए दूसरी भाषा (JS) सीखने की आवश्यकता नहीं है क्योंकि Turbo Turbo Drive, Frames, Streams, और Native द्वारा पूरक है। Drive लिंक्स और फॉर्म्स को तेज करता है और नेटवर्क रीलोड की आवश्यकता को कम करता है, जबकि Frames नेटवर्क को स्वतंत्र संदर्भों में विभाजित करता है जो लोड करने में आसान होते हैं।
Rails के साथ इसका उपयोग कैसे किया जाता है?
यह खंड आपको एक चरण-दर-चरण उदाहरण दिखाएगा।
इस उदाहरण के लिए, हमें आवश्यकता होगी:
- Ruby
- Ruby on Rails
- Redis
- SQLite (डिफ़ॉल्ट डेटाबेस)
- Gem Hotwire
- TurboRails
- StimulusJS
- WebSocket
- ActionCable
हम कौन सा प्रोजेक्ट बनाएंगे?
हम एक सोशल मीडिया प्रोजेक्ट बनाएंगे।
सबसे पहले, अपना टर्मिनल खोलें। आइए एक नए Rails प्रोजेक्ट से शुरू करें:
rails new social-media
अपने प्रोजेक्ट में प्रवेश करें:
cd social-media
Hotwire जोड़ना
अपने प्रोजेक्ट में Hotwire जेम जोड़ें:
bundle add hotwire-rails
वैकल्पिक रूप से, अपना Gemfile खोलें और यह जोड़ें:
gem "hotwire-rails"
यदि आप दूसरे विकल्प का उपयोग करते हैं, तो आपको अब bundle चलाने की आवश्यकता होगी।
bundle install
फिर, आप इसे इंस्टॉल करेंगे।
rails hotwire:install
प्रारंभिक सेटिंग्स
अब Hotwire द्वारा बनाई गई प्रारंभिक सेटिंग्स का विश्लेषण करने का एक अच्छा समय है। Gemfile पर जाने पर, यह इस तरह दिखना चाहिए:
gem 'redis', '~> 4.0'
हमें Redis की आवश्यकता क्यों है?
Redis जेम जोड़ा गया था क्योंकि ActionCable को WebSocket ब्राउज़ करते समय कुछ अस्थायी डेटा स्टोर करने के लिए इसकी आवश्यकता होती है। हालांकि, सिर्फ Redis इंस्टॉल करना इसका उपयोग करने के लिए पर्याप्त नहीं है। हमें यह जांचने की आवश्यकता है कि क्या यह सही ढंग से कॉन्फ़िगर किया गया है। जब आप config/cable.yml फाइल पर जाते हैं, तो यह इस तरह दिखना चाहिए:
development:
adapter: redis
redis://localhost:6379/1
सुनिश्चित करें कि जब आप अपना एप्लिकेशन शुरू करते हैं तो Redis चल रहा है (redis-server)।
JS निर्भरताएं
package.json पर निर्भरताएं जांचें:
dependencies: {
@hotwired/turbo-rails: ^7.0.0-beta.5,
@rails/actioncable: ^6.0.0,
@rails/activestorage: ^6.0.0,
@rails/ujs: ^6.0.0,
@rails/webpacker: 4.3.0,
stimulus: ^2.0.0
}
हमारा मॉडल जेनरेट करना
सभी फाइलों की जांच करने के बाद, हम body और likes कॉलम के साथ posts टेबल के लिए views, controllers, models और migrations जेनरेट करेंगे। ऐसा करने के लिए, टर्मिनल में निम्नलिखित चलाएं:
rails g scaffold posts body:text likes:integer
हमारा डेटाबेस बनाना
अब जब हमारे पास सब कुछ जेनरेट हो गया है, तो हमें इन परिवर्तनों को डेटाबेस में भेजने की आवश्यकता है, इसलिए टर्मिनल में निम्नलिखित चलाएं:
rails db:create db:migrate
यदि सब कुछ ठीक हो जाता है, तो हम सर्वर चला सकते हैं (rails server) और जांच सकते हैं कि सब कुछ ठीक है या नहीं। ऐसा करने के लिए, हम सर्वर चलाएंगे और फिर posts पेज पर जाएंगे, जो https://localhost:3000/posts होगा:
पोस्ट डायरेक्टरी का प्रिंटस्क्रीन
पोस्ट सूचीबद्ध करना
अब, हम पोस्ट सूचीबद्ध करेंगे। ऐसा करने के लिए, हम app/views/posts/_post.html.erb फाइल बनाएंगे और इसमें निम्नलिखित कोड जोड़ेंगे:
<div style="background: lightgrey; width: 300px; padding: 10px;">
<%= post.body %>
<br>
<%= link_to :edit, edit_post_path(post) %>
<%= button_to "likes (#{post.likes || 0})", post_path(post, like: true), method: :put %>
</div>
<br>
वैलिडेशन्स
हमें बॉडी फील्ड को मान्य करने की आवश्यकता है (जो null नहीं हो सकता), और हम प्रसारण को बताएंगे कि एक ट्वीट को पहले ट्वीट के समान स्क्रीन पर बनाने के बाद प्रदर्शित करे। ऐसा करने के लिए, हम app/models/post.rb फाइल को संपादित करेंगे और निम्नलिखित कोड डालेंगे:
class Post < ApplicationRecord
validates_presence_of :body
after_create_commit { broadcast_prepend_to :posts }
end
क्रमबद्ध करना
हमें अपने पोस्ट को क्रमबद्ध करना होगा, इसलिए अपना कंट्रोलर खोलें (app/controllers/posts_controller.rb)।
...
def index
@posts = Post.all.order(created_at: :desc)
@post = Post.new
end
...
समेटना
अब, आइए अपने index (app/views/posts/index.html.erb) को संपादित करें ताकि new post पेज और सभी posts की सूची दिखाई दे।
<%= turbo_stream_from :posts %>
<%= turbo_frame_tag :post_form do %>
<%= render 'posts/form', post: @post %>
<% end %>
<%= turbo_frame_tag :posts do %>
<%= render @posts %>
<% end %>
इंडेक्स पर रीडायरेक्ट करना
अंत में, आइए अपने कंट्रोलर में create मेथड को संशोधित करें। हमें show post पेज पर रीडायरेक्ट करने से बचने के लिए, आइए सब कुछ उसी पेज पर रखें।
...
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to posts_path }
format.json { render :show, status: :created, location: @post }
else
format.turbo_stream { render turbo_stream: turbo_stream.replace(@post, partial: 'posts/form', locals: { post: @post }) }
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
...
हमारा अंतिम पेज इस तरह दिखना चाहिए:
अंतिम पेज का प्रिंटस्क्रीन
लॉग्स की जांच
जब एक पोस्ट बनाया जाता है, तो अपने टर्मिनल लॉग्स देखें; वे इस तरह दिखने चाहिए:
[ActionCable] Broadcasting to posts: "<turbo-stream action=\"prepend\" target=\"posts\"><template><div style=\"background: lightgrey; width: 300px; padding: 10px;\">\n first post\n <br>\n <a href=\"/posts/1/edit\">edit</a>\n <form class=\"button_to\" method=\"post\" action=\"/posts/4?like=true\"><input type=\"hidden\" name=\"_method\" value=\"put\" /><input type=\"submit\" value=\"likes (0)\" /><input type=\"hidden\" name=\"authenticity_token\" value=\"<token>==\" /></form>\n</div>\n<br>\n</template></turbo-stream>"
विचार
इसका मतलब है कि ActionCable Turbo Stream के साथ सुपर फास्ट प्रदर्शन के साथ काम कर रहा है, जैसा कि आप देख सकते हैं: Completed 302 Found in 18ms।
डेप्लॉय करना
क्या हमें अपने Rails सर्वर के साथ चलाने के लिए एक और एक्जीक्यूटेबल की आवश्यकता है?
नहीं, क्योंकि ActionCable लोकप्रिय सर्वर्स जैसे Unicorn, Puma, और Passenger के साथ ठीक काम करता है।
क्या Heroku Hotwire का समर्थन करता है?
हां, Heroku Hotwire के आधार (वेबसॉकेट्स) का समर्थन करता है। यदि आपके कोई और प्रश्न हैं, तो आप Heroku के आधिकारिक दस्तावेज़ देख सकते हैं।
यदि आप सोच रहे हैं कि हम Redis का उपयोग क्यों कर रहे हैं, तो एक और कारण है
यदि Redis के बिना Heroku का उपयोग किया जाता है, तो जब आपका ऐप एक से अधिक डाइनो में स्केल किया जाता है तो मैसेजेस सभी को नहीं भेजे जाएंगे। वर्तमान ऐप की स्टेटलेस प्रकृति के कारण, पहले डाइनो से जुड़े क्लाइंट्स को दूसरे डाइनो से जुड़े क्लाइंट्स द्वारा भेजे गए मैसेजेस नहीं मिलेंगे। Redis मैसेज स्टेट को ग्लोबल स्टोरेज में संग्रहीत करके इस समस्या को हल करता है।
Heroku पर Redis सेटअप करें
अपने रिमोट Redis इंस्टेंस के साथ एक Redis CLI सत्र स्थापित करने के लिए, heroku redis:cli का उपयोग करें। यदि आप कोई इंस्टेंस निर्दिष्ट नहीं करते हैं, तो REDIS_URL पर स्थित इंस्टेंस डिफ़ॉल्ट रूप से उपयोग किया जाता है। यदि आपके पास एक से अधिक इंस्टेंस हैं, तो उस इंस्टेंस को निर्दिष्ट करें जिससे आप कनेक्ट करना चाहते हैं।
एप्लिकेशन सर्वर पर यह कैसे काम करता है?
हमें प्रत्येक डाइनो को Redis पब-सब सिस्टम का उपयोग करने के लिए सेटअप करने की आवश्यकता है। सभी डाइनो एक ही चैनल (डिफ़ॉल्ट) की सदस्यता लेंगे और मैसेजेस की प्रतीक्षा करेंगे। जब प्रत्येक सर्वर को एक मैसेज मिलता है, तो यह इसे जुड़े क्लाइंट्स को प्रकाशित कर सकता है। हम subscribe को एक अलग थ्रेड में कवर करेंगे, क्योंकि subscribe एक ब्लॉकिंग फंक्शन है, इसलिए मैसेज की प्रतीक्षा करने से निष्पादन प्रवाह रुक जाएगा। इसके अलावा, एक दूसरी Redis कनेक्शन की आवश्यकता है क्योंकि एक बार एक कनेक्शन पर सब्सक्राइब कमांड दिए जाने के बाद, कनेक्शन केवल अनसब्सक्राइब या मैसेज प्राप्त कर सकता है। स्केलिंग के बारे में यहां और जानें।
सुरक्षा
वर्तमान में, एप्लिकेशन कई हमलों के प्रति उजागर और कमजोर है। कृपया WSS सेटअप करें और अपने इनपुट को साफ करें। WebSocket सुरक्षा के बारे में यहां और जानें।
निष्कर्ष
जैसा कि हमने यहां दिखाया है, एक नए एप्लिकेशन के माध्यम से Hotwire का उपयोग करना संभव है, लेकिन Turbolinks से अपडेट करना भी संभव है।
इस लेख ने आपको यह समझने में मदद की होगी कि "जादू फ्रेमवर्क" कैसे काम करता है। इसमें, आपको अभ्यास में एक छोटा सरल एप्लिकेशन विकसित करने की संभावना थी जो मैनिपुलेशन और नेविगेशन के साथ WebSocket के माध्यम से एक एग्रीगेटेड टर्बो स्ट्रीम के माध्यम से अनुरोध दिखाता है।