Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

React से प्रेरित, ViewComponents Ruby ऑब्जेक्ट्स हैं जिनका उपयोग व्यू रेंडर करने के लिए मार्कअप बनाने के लिए किया जाता है। ViewComponent Rails में पुन: प्रयोज्य, टेस्टेबल, और एनकैप्सुलेटेड व्यू कंपोनेंट बनाने के लिए एक फ्रेमवर्क है। आमतौर पर, पुन: प्रयोज्य व्यू Rails में पार्शियल का उपयोग करके बनाए जाते हैं और फिर आवश्यकतानुसार अलग-अलग व्यू में रेंडर किए जाते हैं, लेकिन ViewComponent जेम की शुरूआत के साथ, पार्शियल को व्यू कंपोनेंट्स के लिए स्वैप किया जा सकता है, क्योंकि वे अधिक लाभ प्रदान करते हैं। आइए देखते हैं कि ये फायदे क्या हैं।

मुझे ViewComponents का उपयोग कब और क्यों करना चाहिए?

जैसा कि पहले कहा गया है, व्यू कंपोनेंट्स पुन: प्रयोज्य और टेस्टेबल हैं। इसलिए, उन्हें तब लागू किया जा सकता है जब किसी व्यू का पुन: उपयोग किया जाना हो या उससे सीधे टेस्ट होने से लाभ हो। इसके दस्तावेज़ीकरण में बताए गए व्यू कंपोनेंट्स के कुछ लाभों में निम्न शामिल हैं:

  • वे पार्शियल से ~10x तेज़ हैं।
  • वे Ruby ऑब्जेक्ट्स हैं; इसलिए, उनका इनिशियलाइज़ मेथड स्पष्ट रूप से परिभाषित करता है कि व्यू रेंडर करने के लिए क्या आवश्यक है। इसका अर्थ है कि उन्हें समझना और कई अन्य व्यू में पुन: उपयोग करना आसान है। इसके अलावा, Ruby कोड के गुणवत्ता मानकों को लागू किया जा सकता है, जिससे बग का जोखिम कम होता है।
  • उन्हें यूनिट टेस्ट किया जा सकता है, जबकि Rails के पारंपरिक व्यू के लिए इंटीग्रेशन टेस्ट की आवश्यकता होती है जो व्यू के अलावा रूटिंग और कंट्रोलर लेयर्स को भी एक्सरसाइज करते हैं।

ViewComponent कार्यान्वयन

ViewComponents ViewComponent::Base के सबक्लास हैं और app/components में रहते हैं। उनके नाम -Component में समाप्त होते हैं, और उन्हें उनके द्वारा रेंडर किए जाने के लिए नामित किया जाना चाहिए न कि उनके द्वारा स्वीकार किए जाने के लिए। हम जेम को अपने जेमफाइल में जोड़कर और पहले bundle install चलाकर या तो मैन्युअली या कंपोनेंट जनरेटर के माध्यम से एक व्यू कंपोनेंट जनरेट कर सकते हैं।

gem "view_component", require: "view_component/engine"

जनरेटर का उपयोग करने के लिए, निम्न कमांड चलाएँ:

rails generate component  

उदाहरण के लिए, यदि हम एक लर्निंग प्लेटफॉर्म पर उपलब्ध इन-क्लास कोर्स की सूची प्रदर्शित करने के लिए जिम्मेदार एक कंपोनेंट जनरेट करना चाहते हैं, तो हम इस कमांड का उपयोग कर सकते हैं:

rails g component Course course

हम course आर्गुमेंट को कमांड में पास कर रहे हैं क्योंकि हम इस Ruby ऑब्जेक्ट को उस कोर्स के साथ इनिशियलाइज़ करेंगे जिसे हम इसे प्रदर्शित करने की उम्मीद करते हैं, और हमने इसका नाम Course रखा क्योंकि यह एक कोर्स रेंडर करता है। क्या संयोग है!

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

जैसा कि हम ऊपर देख सकते हैं, कंपोनेंट और उसका संबंधित व्यू app/components फ़ोल्डर में बनाए गए हैं, साथ ही एक टेस्ट फाइल।

ViewComponent erb, haml, और slim टेम्पलेट इंजन के लिए टेम्पलेट जनरेटर शामिल करता है लेकिन config.generators.template_engine में निर्दिष्ट टेम्पलेट इंजन पर डिफ़ॉल्ट होगा। फिर भी, आप निम्न का उपयोग करके अपने पसंदीदा टेम्पलेट इंजन को इंगित कर सकते हैं:

rails generate component Course course --template-engine 

आइए हमारे Course मॉडल और प्रदर्शित करने के लिए कुछ कोर्स बनाने के लिए आगे बढ़ें।

rails g model Course title:string price:decimal location:string
rails db:migrate

हमारे कंसोल में, हम जल्दी से दो नए कोर्स बना सकते हैं:

Course.create(title: 'The Art of Learning', price: 125.00, location: 'Denmark')
Course.create(title: 'Organizing your Time', price: 55.00, location: 'London')

course_component.rb फाइल इनिशियलाइज़ मेथड के साथ जनरेट होती है, जैसा कि नीचे दिखाया गया है।

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

हमें एक कोर्स कंट्रोलर बनाने की आवश्यकता है जो हमें कोर्स की सूची पर रूट करे।

rails g controller Courses index

हमारे routes.rb फाइल में, हम निम्न जोड़कर अपने रूट रूट को इंगित करते हैं:

root 'courses#index'

अब जब हम पूरी तरह से सेट हैं, तो अगला कदम व्यू निर्माण है। यह पहले से जनरेटेड course_component.html.erb में किया जाता है।

<%= @course.title %>

<%= number_to_currency(@course.price, :unit => "€") %>

<%= @course.location %>

हमारे व्यू में, हम @course वेरिएबल का उपयोग करके कोर्स शीर्षक, मूल्य, और स्थान प्रदर्शित करते हैं, जिसे हमारे CourseComponent के इनिशियलाइज़ मेथड में पहले से परिभाषित किया गया था। यह तब समान है जब आप एक कंट्रोलर मेथड में एक वेरिएबल बनाते हैं, और फिर यह एक व्यू में उपलब्ध होता है।

यह जानते हुए कि कंट्रोलर कैसे काम करते हैं, हम अपने इंडेक्स मेथड के संबंधित index.html.erb पर रूट होंगे। इसलिए, यहीं हम अपना कंपोनेंट रेंडर करते हैं।

#app/views/courses/index.html.erb
<%= render(CourseComponent.new(course: Course.find(1))) %>

ऊपर देखा गया है कि हम अपने CourseComponent के एक नए इंस्टेंस को उस कोर्स के साथ इनिशियलाइज़ करके रेंडर करते हैं जिसे हम इसके व्यू में रेंडर करने का इरादा रखते हैं। यह कोर्स @course वेरिएबल बन जाता है जो course_component.html.erb फाइल को उपलब्ध कराया जाता है।

इस कंपोनेंट को सीधे हमारे कंट्रोलर से रेंडर करना भी संभव है, जिससे इंडेक्स फाइल व्यू को बायपास किया जाता है:

class CoursesController < ApplicationController
  def index
    render(CourseComponent.new(course: Course.find(1)))
  end
end

आप चाहे जिस मेथड को चुनें, यह सर्वर पर दिखाई देगा:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

अतिरिक्त सामग्री को निम्न में से किसी एक तरीके से कंपोनेंट में भी पास किया जा सकता है:

<%= render(CourseComponent.new(course: Course.find(1))) do %> container <% end %>
<%= render(CourseComponent.new(course: Course.find(1)).with_content("container")) %>

हमारे व्यू कंपोनेंट फाइल में, हम सामग्री को जहाँ चाहें शामिल कर सकते हैं। इस मामले में, हम इसे एक क्लास के रूप में शामिल करेंगे हमारे डिव को ऐसा दिखाने के लिए:

>

उपरोक्त सभी अतिरिक्त सामग्री रेंडर करने के तरीके नीचे दी गई छवि देते हैं:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

कलेक्शन रेंडर करना

क्या होगा यदि हम अपनी पूरी कोर्स सूची रेंडर करना चाहते थे? ViewComponent with_collection टैग का उपयोग करके इसे करने का एक बहुत सीधा तरीका प्रदान करता है। कंपोनेंट को .new का उपयोग करके इनिशियलाइज़ करने के बजाय, इसे .with_collection का उपयोग करके इनिशियलाइज़ किया जाता है, और कलेक्शन को एक वेरिएबल के रूप में पास किया जाता है, जैसा कि नीचे दिखाया गया है।

CourseComponent.with_collection(Course.all)

यह निम्नलिखित देता है:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

एक with_collection_parameter टैग भी उपलब्ध है यदि हम कलेक्शन को किसी अलग नाम से संबोधित करना चाहते हैं।

class CourseComponent < ViewComponent::Base
  with_collection_parameter :item
  def initialize(item:)
    @item = item
  end
end

उपरोक्त मामले में, कोर्स पैरामीटर को item के रूप में संबोधित किया गया है। इसलिए, संबंधित व्यू में, @course को @item से बदल दिया जाएगा ताकि वही परिणाम प्राप्त हो सके।

कलेक्शन में अतिरिक्त पैरामीटर भी जोड़े जा सकते हैं। ये पैरामीटर कलेक्शन में प्रति आइटम प्रदर्शित किए जाएंगे। आइए इस मेथड के माध्यम से प्रत्येक आइटम में Buy Me टेक्स्ट जोड़ें।

#app/views/courses/index.html.erb
<%= render(CourseComponent.with_collection(Course.all, notice: "Buy Me")) %>
# app/components/course_component.rb
class CourseComponent < ViewComponent::Base
  with_collection_parameter :item
  def initialize(item:, notice:)
    @item = item
    @notice = notice
  end
end

हम नए नोटिस वेरिएबल के लिए टेक्स्ट इंगित करने के लिए app/components/course_component.html.erb फाइल में एक नया पैराग्राफ जोड़ते हैं।

<%= @notice %>

यह निम्नलिखित देता है:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

अंत में, कलेक्शन के तहत, हमारे पास एक काउंटर वेरिएबल है जिसे व्यू में आइटम नंबर देने के लिए सक्षम किया जा सकता है। यह कलेक्शन पैरामीटर में _counter जोड़कर और इसे इनिशियलाइज़ मेथड के माध्यम से व्यू के लिए उपलब्ध कराकर सक्षम किया जाता है।

#app/components/course_component.rb
def initialize(item:, notice:, item_counter:)
  @item = item
  @notice = notice
  @counter = item_counter
end

हमारे व्यू में, आइटम शीर्षक के बगल में, हम अपना काउंटर जोड़ते हैं:

<%= @counter %>. <%= @item.title %>

आइए कंसोल से एक तीसरा कोर्स जनरेट करें ताकि काउंटर घटना को बेहतर ढंग से समझा जा सके।

Course.create(title: 'Understanding Databases', price: '100', location: 'Amsterdam')

यह निम्नलिखित देता है

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

सशर्त रेंडरिंग

ViewComponent में एक render? हुक है, जिसका उपयोग करने पर यह निर्धारित करता है कि किसी व्यू को रेंडर किया जाना चाहिए या नहीं। इसे लागू करने के लिए, हम 100 यूरो के बराबर या उससे अधिक कीमत वाले कोर्स पर 10% छूट देने जा रहे हैं। आइए इस उद्देश्य के लिए एक कंपोनेंट बनाएँ।

rails generate component Discount item

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

यह कंपोनेंट पहले से ही उस आइटम के साथ स्वचालित रूप से इनिशियलाइज़ है जिसके लिए इसे छूट प्रदर्शित करनी चाहिए, जैसा कि नीचे देखा गया है।

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

इसलिए, discount_component.html.erb फाइल में, हम वह टेक्स्ट जोड़ते हैं जिसे हम प्रदर्शित करना चाहते हैं।

A 10% discount is available on this course

अपने सीएसएस फाइल में green क्लास जोड़ने में संकोच न करें और अपनी पसंद का कोई भी हरा रंग असाइन करें। इसके अलावा, हमारे discount_component.rb फाइल में, हम render? मेथड जोड़ते हैं ताकि यह निर्धारित किया जा सके कि इस कंपोनेंट को कब रेंडर किया जाना चाहिए।

def render?
  @item.price >= 100
end

अब, हम आगे बढ़ सकते हैं और प्रत्येक कोर्स को रेंडर करने वाले व्यू के भीतर डिस्काउंट कंपोनेंट को रेंडर कर सकते हैं।

# app/components/course_component.html.erb
<%= render(DiscountComponent.new(item: @item)) %>

यह निम्नलिखित देता है:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

क्या यह बहुत बढ़िया नहीं है?

हेल्पर्स

पारंपरिक Rails व्यू में, हम मेथड नाम को अपने व्यू में कॉल करके आसानी से अपने हेल्पर्स में प्लग इन कर सकते हैं, लेकिन यह व्यू कंपोनेंट्स के साथ अलग तरह से काम करता है। व्यू कंपोनेंट्स में, हेल्पर मेथड्स को व्यू में सीधे कॉल नहीं किया जा सकता लेकिन एक कंपोनेंट में शामिल किया जा सकता है। हमारे पास पहले से ही एक courses_helper.rb फाइल है जो CoursesController बनाए जाने पर स्वचालित रूप से जनरेट हुई थी, तो आइए इसका लाभ उठाएं। पहले, आइए एक हेल्पर मेथड बनाएं जो हमें बताता है कि अब तक एक कोर्स में कितने लोग नामांकित हुए हैं। आइए मान को कीमत का एक चौथाई बनाएं :).

module CoursesHelper
  def count_enrollees(course)
    count = (course.price / 4).round()
    tag.p "#{count} enrollees so far"
  end
end

अगला, हम एक कंपोनेंट बनाएंगे जिसमें हम हेल्पर को कॉल करेंगे। यह वह कंपोनेंट है जिसे हमारे व्यू में रेंडर किया जाएगा। इसमें, हम एक include स्टेटमेंट जोड़ेंगे, जिसमें हेल्पर शामिल होगा, और फिर हम इस कंपोनेंट के भीतर हेल्पर में किसी भी मेथड को कॉल कर सकते हैं।

# app/components/enrollee_component.rb
class EnrolleeComponent < ViewComponent::Base
  include CoursesHelper
  def total_enrollees(course)
    count_enrollees(course)
  end
end

अंतिम चरण हमारे कोर्स प्रदर्शित करने वाले व्यू में EnrolleeComponent को जोड़ना है।

# app/components/course_component.html.erb
<%= EnrolleeComponent.new.total_enrollees(@item) %>

ध्यान दें कि हम EnrolleeComponent के लिए रेंडर शब्द का उपयोग नहीं कर रहे हैं, क्योंकि इसका कोई व्यू नहीं है, और इसका आउटपुट कॉल किए गए हेल्पर मेथड का होगा। यह निम्नलिखित देता है:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

हेल्पर्स का उपयोग आइकन, ग्रेविटार, या जो भी आप चुन सकते हैं के लिए किया जा सकता है। ViewComponent हेल्पर्स के उपयोग को नहीं बदलता; यह सिर्फ बदलता है कि हम उन्हें अपने कंपोनेंट में कैसे कॉल करते हैं।

before_render मेथड

ViewComponent एक before_render मेथड प्रदान करता है जिसे कंपोनेंट रेंडर होने से पहले बुलाया जा सकता है। आइए हमारे डिस्काउंट नोटिस के बगल में एक स्टार जोड़ें। हम एक हेल्पर मेथड जोड़कर शुरू करते हैं जो स्टार लाता है; एक star.png इमेज भी डाउनलोड की गई है और app/assets/images फ़ोल्डर में रखी गई है।

#app/helpers/courses_helper.rb
def star_icon
  image_tag("/assets/star.png", width: "1%")
end

आइए अपने Discount कंपोनेंट में एक before_render मेथड जोड़ें जो इस हेल्पर मेथड को कॉल करता है।

# app/components/discount_component.rb
def before_render
  @star_icon = helpers.star_icon
end

जैसा कि हम ऊपर देख सकते हैं, हेल्पर्स को कॉल करने का एक और तरीका पेश किया गया है। हेल्पर्स को कंपोनेंट.rb फाइल में helpers.method का उपयोग करके भी बुलाया जा सकता है। फिर, DiscountComponent के लिए हमारे रेंडर मेथड में, हम अपना स्टार आइकन इनपुट करते हैं, जो अब @star_icon वेरिएबल के माध्यम से उपलब्ध है।

# app/components/discount_component.html.erb

<%= @star_icon %> A 10% discount is available on this course

यह निम्नलिखित देता है:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

हम before_render मेथड के काम करने के लिए हेल्पर्स का उपयोग करना आवश्यक नहीं है। मैंने एक और दृष्टिकोण पेश करने के लिए हेल्पर्स का उपयोग किया है।

प्रीव्यू

Action Mailer की तरह, ViewComponent कंपोनेंट्स का प्रीव्यू करना संभव बनाता है। इसे पहले config/application.rb फाइल में सक्षम करना होगा।

config.view_component.preview_paths << "#{Rails.root}/lib/component_previews"

प्रीव्यू कंपोनेंट्स test/components/previews में स्थित हैं और कई अलग-अलग इनपुट्स के साथ एक कंपोनेंट का प्रीव्यू करने के लिए उपयोग किए जा सकते हैं। हम अपने DiscountComponent का प्रीव्यू करेंगे।

# test/components/previews/discount_component_preview.rb
class DiscountComponentPreview < ViewComponent::Preview
  def with_first_course
    render(DiscountComponent.new(item: Course.find(1)))
  end

  def with_second_course
    render(DiscountComponent.new(item: Course.find(2)))
  end
end

दो मेथड्स डिस्काउंट कंपोनेंट को विभिन्न परिदृश्यों में प्रीव्यू करने के लिए जोड़े गए हैं। इसे देखने के लिए, https://localhost:3000/rails/view_components पर जाएँ, जहां हमें सभी बनाए गए प्रीव्यू कंपोनेंट्स और उनके मेथड्स मिलते हैं। हम उनमें से किसी पर भी क्लिक करके देख सकते हैं कि वे कैसे दिखते हैं, जैसा कि नीचे दिखाया गया है।

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

जैसा कि आप ऊपर वीडियो में देख सकते हैं, पहला कोर्स डिस्काउंट कंपोनेंट को रेंडर करता है, लेकिन दूसरे कोर्स के लिए कुछ भी रेंडर नहीं होता। क्या आप जानते हैं कि ऐसा क्यों हुआ? render? मेथड चेक हुआ। पहला परिदृश्य वह है जब लागत मूल्य 100 यूरो से अधिक है (पहला कोर्स), लेकिन दूसरे कोर्स के लिए लागत 100 यूरो से कम है। मेथड नाम अधिक वर्णनात्मक नहीं थे ताकि आप इसे यहाँ हाइलाइट होने से पहले पता लगा सकें :).

प्रीव्यू को किसी भी वातावरण में show_previews विकल्प का उपयोग करके सक्षम या अक्षम किया जा सकता है, लेकिन विकास और टेस्टिंग वातावरण में, वे डिफ़ॉल्ट रूप से सक्षम हैं।

# config/environments/test.rb
config.view_component.show_previews = false

JS और CSS शामिल करना

कंपोनेंट्स के साथ JavaScript और CSS शामिल करना संभव है, जिसे कभी-कभी "साइडकार" एसेट्स या फाइलें कहा जाता है। यह अभी भी एक एक्सपेरिमेंटल फीचर है। इसलिए, हम इस लेख में इसके आंतरिक कामकाज में गोता नहीं लगाएंगे, लेकिन आप इस ViewComponent फीचर के बारे में यहाँ और अधिक जान सकते हैं।

टेम्पलेट्स

व्यू कंपोनेंट का टेम्पलेट कई तरीकों से परिभाषित किया जा सकता है। सरल विकल्प व्यू और कंपोनेंट को एक ही फ़ोल्डर में डालना है, जैसा कि नीचे दिखाया गया है।

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

जैसा कि हम यहाँ देख सकते हैं, हमारे पास app/components फ़ोल्डर में हर कंपोनेंट और व्यू है।

एक अन्य विकल्प व्यू और अन्य एसेट्स को कंपोनेंट के समान नाम वाले सबडायरेक्टरी में रखना है। इस प्रकार, app/components फ़ोल्डर में, हमारे पास component.rb फाइल है, जिसमें कंपोनेंट होता है, और फिर एक अलग course_component फ़ोल्डर, जिसमें व्यू course_component.html.erb और कोर्स_कंपोनेंट से संबंधित हर दूसरी संपत्ति होती है।

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

कमांड लाइन से इस तरह कंपोनेंट फाइल जनरेट करने के लिए, --sidecar फ्लैग आवश्यक है:

rails g component Example name --sidecar

यह आपको अपने सीएसएस और जेएस फाइलों को कंपोनेंट फ़ोल्डर में जोड़ने में सक्षम बनाता है। ViewComponents एक call मेथड को परिभाषित करके टेम्पलेट फाइल के बिना भी रेंडर कर सकते हैं। इसका एक उदाहरण अगले भाग में प्रदान किया गया है, जहां हम स्लॉट्स पर चर्चा करते हैं।

स्लॉट्स

कंटेंट के कई ब्लॉक्स को एक सिंगल ViewComponent में स्लॉट्स का उपयोग करके पास किया जा सकता है। Rails मॉडल में has_one और has_many एट्रिब्यूट्स के समान, स्लॉट्स को renders_one और renders_many के साथ परिभाषित किया जाता है:

  • renders_one एक स्लॉट को परिभाषित करता है जिसे प्रति कंपोनेंट अधिकतम एक बार रेंडर किया जाएगा: renders_one :header.
  • renders_many एक स्लॉट को परिभाषित करता है जिसे प्रति कंपोनेंट कई बार रेंडर किया जा सकता है: renders_many :titles.

कल्पना करें कि हम एक पेज चाहते हैं जो एक हेडर और हमारे पास उपलब्ध सभी कोर्स के शीर्षक रेंडर करता है; इसे स्लॉट्स का उपयोग करके प्राप्त किया जा सकता है। आइए एक ListComponent बनाएँ, जिसमें एक हेडर होगा जो केवल एक बार रेंडर होगा, और एक TitleComponent, जो कई शीर्षक रेंडर करता है।

#app/components/list_component.rb
class ListComponent < ViewComponent::Base
  renders_one :header, "HeaderComponent"
  # `HeaderComponent` को इस कंपोनेंट के भीतर परिभाषित किया गया है, इसलिए हम इसे स्ट्रिंग का उपयोग करके संदर्भित करते हैं।
  renders_many :titles, TitleComponent
  # `titleComponent` को किसी अन्य फाइल में परिभाषित किया जाएगा, इसलिए हम इसे क्लास नाम से संदर्भित कर सकते हैं।

  class HeaderComponent < ViewComponent::Base
    def call
      content_tag :h1, content
    end
  end
end

ऊपर के कंपोनेंट में, हमने कहा कि हेडर एक बार रेंडर होता है, लेकिन शीर्षक कई बार रेंडर होते हैं, क्योंकि इस पेज में कई शीर्षक होंगे। हमने ListComponent के भीतर HeaderComponent को भी परिभाषित किया है। हाँ, यह ViewComponent के साथ संभव है; एक क्लास को दूसरी क्लास के भीतर परिभाषित किया जा सकता है। आइए टेम्पलेट्स सेक्शन के तहत पहले चर्चा किए गए कॉल मेथड पर भी ध्यान दें और यह HeaderComponent में h1 टैग रेंडर करने के लिए कैसे उपयोग किया जा रहा है, जिससे संबंधित व्यू (html.erb फाइल) की आवश्यकता समाप्त हो जाती है। ListComponent के लिए संबंधित HTML फाइल में निम्न होगा;

#app/components/list_component.html.erb
<%= header %> <% titles.each do |title| %>
<%= title %>
<% end %>

HTML फाइल में, हमने हेडर को शामिल किया, कंपोनेंट में पास किए गए सभी शीर्षकों के माध्यम से पुनरावृति की, और उन्हें रेंडर किया। जैसा कि आप देख सकते हैं, हमें लिस्ट व्यू फाइल में रेंडर किए जाने वाले कंपोनेंट का नाम निर्दिष्ट करने की आवश्यकता नहीं है; हमारे स्लॉट्स ने इसका ध्यान रखा है। इसलिए, हम उन्हें केवल header और title के रूप में पहचानते हैं।

अगला कदम हमारे TitleComponent और इसकी संबंधित HTML फाइल बनाना है, क्योंकि यह वही है जो पास किए गए हर शीर्षक के लिए रेंडर किया जाएगा।

# app/components/title_component.rb
class TitleComponent < ViewComponent::Base
  def initialize(title:)
    @title = title
  end
end
# app/components/title_component.html.erb

<%= @title %>

अंत में, हमारे index.html फाइल में, आइए अस्थायी रूप से जो हमारे पास है उसे मिटा दें और इसे ListComponent रेंडर से बदलें।

#app/views/courses/index.html.erb
<%= render ListComponent.new do |c| %>
  <% c.header do %>
    <%= link_to "List of Available Courses", root_path %>
  <% end %>
  <%= c.title(title: "First title") %>
  <%= c.title(title: "Second title!") %>
<% end %>

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

अब, आइए अपने कोर्स को इस व्यू में कलेक्शन के रूप में पास करें। एक कलेक्शन को स्लॉट में पास करने के लिए, हमें इनिशियलाइज़ेशन के लिए आवश्यक वेरिएबल वाले ऑब्जेक्ट्स की एक सरणी के रूप में कलेक्शन पास करना होगा। जैसा कि हम देख सकते हैं, पास किया गया हर कोर्स शीर्षक आर्गुमेंट के साथ इनिशियलाइज़ होना चाहिए। हम अपने डेटाबेस में सभी कोर्स के शीर्षक को हैश की एक सरणी में निकाल सकते हैं और इसे रेंडर कर सकते हैं।

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

अब हम अपने कई शीर्षकों की सूची को एक सिंगल c.titles से कलेक्शन के लिए बदल सकते हैं और इसे हमारे हैश के शीर्षकों पर पास कर सकते हैं, जिसे हम वेरिएबल course_titles का उपयोग करके परिभाषित करते हैं।

# app/views/courses/index.html.erb
<% course_titles = Course.all.pluck(:title).map { |title| {title: title}} %>
<% c.titles(course_titles) %>

यह निम्नलिखित देता है:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

यही स्लॉट्स काम करते हैं: एक सिंगल ViewComponent के भीतर कई कंपोनेंट रेंडर करना। स्लॉट्स को कई अन्य तरीकों से रेंडर किया जा सकता है, और आप यहाँ अधिक जानकारी पा सकते हैं।

टेस्टिंग

व्यू कंपोनेंट्स का टेस्टिंग टेस्ट फाइल में "view_component/test_case" की आवश्यकता करके और render_inline टेस्ट हेल्पर का उपयोग करके किया जाता है ताकि रेंडर्ड आउटपुट के विरुद्ध दावे किए जा सकें। आइए अपने DiscountComponent का टेस्ट करके शुरू करें।

require "test_helper"
require "view_component/test_case"
class DiscountComponentTest < ViewComponent::TestCase
  def test_render_component
    render_inline(DiscountComponent.new(item: "my item"))
  end
end

जब हम इस टेस्ट को rails test test/components/discount_component_test.rb कमांड का उपयोग करके चलाते हैं, तो हमें निम्न त्रुटि मिलती है:

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

यह हमें साबित करता है कि टेस्ट सही कंपोनेंट तक पहुँच रहा है लेकिन इसमें एक उपयुक्त प्रॉप की कमी है, क्योंकि आइटम एक कोर्स होना चाहिए जिसमें प्राइस प्रॉपर्टी हो न कि एक स्ट्रिंग, जैसा कि हमने पास किया। यह यह भी बताता है कि इस कंपोनेंट के रेंडर होने से पहले render? मेथड चेक किया जा रहा है। आइए अब सही वेरिएबल पास करें।

def test_render_component
  course = Course.create(title: 'Organizing your Time', price: 55.00, location: 'London')
  render_inline(DiscountComponent.new(item: course))
end

यह सफलतापूर्वक चलता है। आइए इस टेस्ट में दावे जोड़ें।

def test_render_component
  course = Course.create(title: 'Organizing your Time', price: 155.00, location: 'London')
  render_inline(DiscountComponent.new(item: course))
  assert_selector 'p[class="green"]'
  assert_text "10% discount"
end

यह टेस्ट भी पास होता है। याद रखें कि इस कंपोनेंट के लिए एक रेंडर कंडीशन है। चिंता न करें, क्योंकि ViewComponent यह टेस्ट करने का एक तरीका भी प्रदान करता है कि कोई कंपोनेंट रेंडर नहीं किया गया है, refute_component_rendered का उपयोग करके। हम 100 यूरो से कम कीमत वाले कोर्स का उपयोग करके इसका टेस्ट कर सकते हैं।

def test_component_not_rendered
  course = Course.create(title: 'Organizing your Time', price: 55.00, location: 'London')
  render_inline(DiscountComponent.new(item: course))
  refute_component_rendered
end

यह टेस्ट भी पास होता है।

आइए अपने CourseComponent के लिए एक और टेस्ट लिखें ताकि यह टेस्ट किया जा सके कि यह इसके भीतर नेस्टेड सभी कंपोनेंट्स को रेंडर करता है।

require "test_helper"
require "view_component/test_case"
class CourseComponentTest < ViewComponent::TestCase
  def test_component_renders_all_children
    course = Course.create(title: 'Organizing your Time', price: 155.00, location: 'London')
    render_inline(CourseComponent.new(item: course, notice: 'A new test', item_counter: 1))
    assert_selector("h2", text: "Organizing your Time")
    assert_selector("h4", text: "€155.00")
    assert_selector("h4", text: "London")
    assert_text("enrollees")
    assert_text("discount")
  end
end

यह टेस्ट भी पास होता है। यह टेस्ट करता है कि Enrollee और Discount कंपोनेंट्स भी ठीक से रेंडर हो रहे हैं।

याद रखें कि हमारे पास एक स्लॉट कंपोनेंट है, और जैसा कि नीचे दी गई छवि में दिखाया गया है, यह एक हेडर और कई शीर्षक रेंडर करता है।

ViewComponent में महारत: पुन: प्रयोज्य Rails व्यू कंपोनेंट बनाने के लिए एक व्यावहारिक गाइड

इसे टेस्ट करने के लिए, हम कंपोनेंट को कोड का एक ब्लॉक पास करते हैं जिसमें हेडर और शीर्षक होते हैं जिन्हें इसे रेंडर करना चाहिए, और फिर हम रेंडर्ड कंपोनेंट के विरुद्ध दावा कर सकते हैं।

require "test_helper"
require "view_component/test_case"
class ListComponentTest < ViewComponent::TestCase
  def test_renders_slots_with_content
    render_inline(ListComponent.new) do |component|
      component.header { "A Test List" }
      component.titles [{title: 'Test title 1'}, {title: 'Test title 2'}]
    end
    assert_selector("h1", text: "A Test List")
    assert_text("Test title 1")
    assert_text("Test title 2")
  end
end

यह टेस्ट भी पास होता है :).

Rspec टेस्टिंग

उपरोक्त टेस्टिंग के बारे में जो कुछ भी कहा गया है, उसके अलावा, यदि पसंदीदा टेस्टिंग फ्रेमवर्क RSpec है, तो ViewComponents के लिए RSpec को सक्षम करने के लिए कुछ अतिरिक्त कॉन्फ़िगरेशन किए जाने चाहिए।

# spec/rails_helper.rb
require "view_component/test_helpers"
require "capybara/rspec"
RSpec.configure do |config|
  config.include ViewComponent::TestHelpers, type: :component
  config.include Capybara::RSpecMatchers, type: :component
end

हमारा DiscountComponent टेस्ट Rspec का उपयोग करके फिर से लिखा और पुनः परीक्षण किया जा सकता है, जैसा कि नीचे दिखाया गया है:

require "rails_helper"
RSpec.describe DiscountComponent, type: :component do
  it "renders the component correctly" do
    course = Course.create(title: 'Organizing your Time', price: 155.00, location: 'London')
    render_inline(DiscountComponent.new(item: course))
    expect(rendered_component).to have_css "p[class='green']", text: "10% discount"
    expect(rendered_component).to have_css "img[src*='/assets/star.png']"
  end
end

यह टेस्ट सुरुचिपूर्ण ढंग से पास होता है। हाँ, हम अपना स्टार आइकन देख सकते हैं।

निष्कर्ष

अपने Rails ऐप के लिए कई व्यू कंपोनेंट लिखना न केवल आपके कोड को अधिक पठनीय और अवांछित जटिलताओं से होने वाली त्रुटियों से कम प्रवण बनाता है बल्कि आपके व्यू को केवल HTTP अनुरोधों के दौरान ही नहीं बल्कि अलगाव में टेस्ट करना भी संभव बनाता है। व्यू कंपोनेंट्स को मौजूदा Rails ऐप में शामिल करना आसान है, और सबसे अच्छा यह है कि उन व्यू से शुरू करें जो ज्यादातर पुन: उपयोग किए जाते हैं। अब तक सीखी गई हर चीज के साथ, यह एक आसान काम होना चाहिए। फिर भी, यदि आप ViewComponent पर अधिक जानकारी चाहते हैं, तो इसके दस्तावेज़ीकरण या RubyDoc जानकारी को देखने में संकोच न करें।

  1. अपने MacBook Pro के लिए आदर्श 4K मॉनिटर चुनना अपने MacBook Pro के लिए आदर्श 4K मॉनिटर चुनना

    क्या आपने 4K मॉनिटर के बारे में सुना है? सबसे अधिक संभावना है, आपने पहले ही इसके बारे में सुना होगा। आखिरकार, यह आजकल काफी लोकप्रिय है। इसके बारे में अच्छी बात यह है कि आप इसे अपने MacBook के साथ उपयोग कर सकते हैं। आप अपने MacBook को मिरर करने के लिए 4K मॉनिटर का उपयोग कर सकते हैं या आप इसे सेकेंडरी

  1. SOLID में मास्टरी: मजबूत सॉफ्टवेयर डिज़ाइन के लिए व्यापक गाइड SOLID में मास्टरी: मजबूत सॉफ्टवेयर डिज़ाइन के लिए व्यापक गाइड

    Kriptofolio ऐप सीरीज़ - भाग 1सॉफ्टवेयर हमेशा बदलाव की स्थिति में होता है। प्रत्येक बदलाव पूरे प्रोजेक्ट पर नकारात्मक प्रभाव डाल सकता है। इसलिए आवश्यक चीज नए बदलावों को लागू करते समय होने वाले नुकसान को रोकना है।Kriptofolio (पहले My Crypto Coins) ऐप के साथ, मैं चरण-दर-चरण बहुत सारा नया कोड बनाऊंगा और

  1. Google Project Fi: निर्बाध मोबाइल कॉलिंग का भविष्य Google Project Fi: निर्बाध मोबाइल कॉलिंग का भविष्य

    वायरलेस नेटवर्क का बाजार भीड़भाड़ वाला है और फिर भी हमें कोई बढ़िया डील नहीं मिलती। वास्तव में, सेल फोन कैरियर्स की खराब प्रतिष्ठा है और जरूरी नहीं कि गलत कारणों से। ऐसा इसलिए है क्योंकि नॉट-सो अनलिमिटेड डेटा प्लान, लगातार बढ़ती डेटा कीमतें और घटती डेटा कैप से संबंधित विवाद हैं। डेटा प्लान पर भारी ख