सवाल रेल के बाद केवल "नया" पर आरंभ करें


मेरे पास निम्नलिखित 2 मॉडल हैं

class Sport < ActiveRecord::Base
  has_many :charts, order: "sortWeight ASC"
  has_one :product, :as => :productable
  accepts_nested_attributes_for :product, :allow_destroy => true
end

class Product < ActiveRecord::Base
  belongs_to :category
  belongs_to :productable, :polymorphic => true
end

एक खेल उत्पाद के बिना मौजूद नहीं हो सकता है, इसलिए मेरे में sports_controller.rb मैंने लिया:

def new
  @sport = Sport.new
  @sport.product = Product.new
...
end

मैंने उत्पाद के निर्माण को खेल मॉडल में इस्तेमाल करने की कोशिश की after_initialize:

after_initialize :create_product

def create_product
 self.product = Product.new
end

मैंने जल्दी ही सीखा after_initialize जब भी एक मॉडल तत्काल होता है तब कहा जाता है (यानी, ए से find कहते हैं)। तो वह व्यवहार नहीं था जिसे मैं ढूंढ रहा था।

जिस तरह से मुझे आवश्यकता को मॉडलिंग करना चाहिए sport लीजिये product?

धन्यवाद


44
2018-03-07 22:42


मूल




जवाब:


जैसा कि आपने कहा था नियंत्रक में तर्क डालना सबसे अच्छा जवाब हो सकता है, लेकिन आप इसे प्राप्त कर सकते हैं after_initialize निम्नलिखित करने के द्वारा काम करने के लिए:

after_initialize :add_product

def add_product
  self.product ||= Product.new
end

इस तरह, यह उत्पाद सेट करता है यदि कोई उत्पाद मौजूद नहीं है। यह ओवरहेड के लायक नहीं हो सकता है और / या नियंत्रक में तर्क होने से कम स्पष्ट हो सकता है।

संपादित करें: प्रति रायन के जवाब के अनुसार, प्रदर्शन के अनुसार निम्न बेहतर होगा:

after_initialize :add_product

def add_product
  self.product ||= Product.new if self.new_record?
end

59
2018-03-08 05:10



इस समाधान का उपयोग करने में मेरी समस्या यह है कि मेरे मामले में, उत्पाद फ़ील्ड शून्य हो सकता है (इसलिए मुझे वास्तव में केवल बाद में बनाने के लिए प्रारंभ करना चाहिए) .. अगर किसी के पास कोई विचार है, तो बहुत अच्छा होगा, धन्यवाद! - yorch
@yorch पहले / बाद_क्रेट से पहले जांचें। यदि आपका तर्क बहुत जटिल है, तो शायद आप इसे पहले / बाद में हुक में छिपाना नहीं चाहते हैं क्योंकि यह भी हो सकता है जादुई। - bostonou
हालांकि, इस विधि को अनुकूलित नहीं किया जाता है, एक बार जब आप बड़ी मात्रा में खेल / उत्पादों का चयन शुरू करते हैं, तो आप देखेंगे कि आपकी क्वेरी बहुत अप्रचलित है क्योंकि आपके रिश्ते के लिए आप यह चुनने के लिए एक चुनिंदा वक्तव्य कर रहे हैं कि उत्पाद मौजूद है या नहीं - YaBoyQuy
@YaBoyQuy आपको शायद उपयोग करना चाहिए includes अपनी क्वेरी पर - उत्सुक लोडिंग सेक्शन देखें api.rubyonrails.org/classes/ActiveRecord/Associations/... - bostonou
@Eric L, जब मैंने पहली बार समस्या को पढ़ा, तो मैंने सोचा कि एक उत्पाद के साथ एक स्पोर्ट ऑब्जेक्ट बनाना एक शर्त है जो मॉडल और व्यापार नियमों से जुड़ी है। यदि यह वास्तव में है, तो आईएमओ यह तर्क डोमेन परत पर मौजूद होना चाहिए न कि दृश्य / ऐप परत (जिसमें नियंत्रक शामिल हैं)। आपके द्वारा सुझाई गई कक्षा विधि एक अच्छा विकल्प है यदि सभी खेलों में कम से कम एक उत्पाद होना चाहिए - Rudy Seidinger


निश्चित रूप से after_initialize :add_product, if: :new_record? यहां सबसे साफ तरीका है।

Add_product फ़ंक्शन के सशर्त से बाहर रखें


29
2017-10-09 09:35



यह शायद जाने का सही तरीका है। - fatuhoku
कर देता है after_initialize :add_product, on: :create काम? - Justin Maxwell


यदि तुम करो self.product ||= Product.new यह हर बार जब भी आप एक उत्पाद की खोज करेंगे find क्योंकि यह जांचने की जरूरत है कि यह शून्य है या नहीं। नतीजतन यह कोई उत्सुक लोडिंग नहीं करेगा। ऐसा करने के लिए केवल जब एक नया रिकॉर्ड बनाया जाता है तो आप उत्पाद को सेट करने से पहले यह जांच सकते हैं कि यह एक नया रिकॉर्ड है या नहीं।

after_initialize :add_product

def add_product
  self.product ||= Product.new if self.new_record?
end

मैंने कुछ बुनियादी बेंचमार्किंग और जांच की if self.new_record? किसी भी ध्यान देने योग्य तरीके से प्रदर्शन को प्रभावित नहीं करता है।


27
2018-05-06 05:10



New_record का आह्वान करके प्रदर्शन के साथ महान काम मारा? ! - conciliator
इसे स्थानांतरित करना भी संभव है new_record? की जाँच करें add_product लेखन से after_initialize :add_product, :if => :new_record?। कुछ मामलों में यह बेहतर संगठित होगा। - Rory O'Kane


के बजाय का उपयोग करने का after_initialize, कैसा रहेगा after_create?

after_create :create_product

def create_product
  self.product = Product.new
  save
end

क्या ऐसा लगता है कि यह आपकी समस्या का समाधान करेगा?


2
2018-03-07 22:58



यह के लिए है new नियंत्रक में विधि .... कुछ भी अभी तक डीबी में सहेजा नहीं जाता है, तो after_create नहीं बुलाया जाएगा - Tyler DeWitt


ऐसा लगता है कि आप बहुत करीब हैं। आपको बाद में कॉल को बाद में कॉल करने में सक्षम होना चाहिए, लेकिन पहले मुझे विश्वास है कि यदि आपके स्पोर्ट मॉडल के पास "हैसोन" रिश्ते है: जैसा कि आपने संकेत दिया है, तो आपके उत्पाद मॉडल को "संबंधित" खेल भी होना चाहिए। इसे अपने उत्पाद मॉडल में जोड़ें

belongs_to: :sport

अगला कदम, अब आप इस तरह के एक स्पोर्ट मॉडल को तुरंत चालू करने में सक्षम होना चाहिए

@sport = @product.sport.create( ... )

यह जानकारी से आधारित है एसोसिएशन मूल बातें रेल गाइड पर रुबी से, जिसे आप पढ़ सकते हैं अगर मैं बिल्कुल सही नहीं हूं


1
2018-03-07 23:15



पॉलिमॉर्फिक एसोसिएशन इसे थोड़ा सा फेंक देता है। एक उत्पाद एक उत्पादक (शब्द बना दिया) से संबंधित है। ऐसा इसलिए है क्योंकि कुछ उत्पाद खेल हैं और कुछ फिल्में हैं (मैं खेल से शुरू कर रहा हूं)। रेलों में विरासत को संभालने के बारे में मेरी समझ है (सिंगल टेबल विरासत के अलावा, जो मैं नहीं चाहता था)। हालांकि विचार के लिए धन्यवाद! - Tyler DeWitt
आह मैं देखता हूं, मुझे मॉडल की बहुलक प्रकृति का एहसास नहीं हुआ था, और बदले में मुझे एहसास हुआ कि मुझे यह नहीं पता कि इसे कैसे संभालना है। मैं इसे अपने आप में भी देखना जारी रखूंगा। अगर मैं कुछ भी लेकर आऊंगा तो मैं आपको बता दूंगा। - coderates
इस railscast ऐसा लगता है कि वह उत्तर शामिल है जिसे आप ढूंढ रहे हैं। ऐसा लगता है कि मैंने ऊपर के प्रयास के रूप में नया खेल बनाने के समान तरीके का उपयोग किया है। उम्मीद है की यह मदद करेगा। - coderates
हां, ऐसा लगता है कि तर्क को नियंत्रक में रखना है। आईआरसी चैनल में कुछ पीपीएल ने भी यही कहा - Tyler DeWitt


आपको बस आरंभिक विधि को ओवरराइड करना चाहिए

class Sport < ActiveRecord::Base

  # ...

  def initialize(attributes = {})
    super
    self.build_product
    self.attributes = attributes
  end

  # ...

end

डेटाबेस से रिकॉर्ड लोड होने पर विधि को प्रारंभ नहीं किया जाता है। ध्यान दें कि उत्पाद के निर्माण के बाद उपरोक्त कोड में कोड असाइन किए गए हैं। ऐसी सेटिंग में विशेषता असाइनमेंट बनाए गए उत्पाद उदाहरण को प्रभावित कर सकता है।


0
2017-09-13 10:41



आपको यहां विस्तृत कारणों से ऐसा नहीं करना चाहिए: stackoverflow.com/questions/4376992/... - tirdadc
नहीं, प्रारंभ करने के लिए ओवरराइड नहीं करने का कोई कारण नहीं है। इसके विपरीत, यदि आप रेल स्रोत कोड में देखते हैं, तो आप समझेंगे कि प्रारंभिकता ओवरराइड करने के लिए थी। आपको बस इतना करना है कि अपने ओवरराइड प्रारंभिक में सुपर को कॉल करना है, लेकिन यह एक नियम है जिसके बाद सभी रूबी डेवलपर्स और रेल डेवलपर्स द्वारा पीछा किया जाने की उम्मीद है, चुपचाप आपको ऐसा करने की उम्मीद है। - Victor Nazarov
मैं ऐसा करने से सावधान रहूंगा क्योंकि यह ऐसी चीज है जो भ्रम पैदा कर सकती है, भविष्य के संस्करणों में तोड़ सकती है, और संभवतः कुछ तीसरे पक्ष के रत्नों के लिए समस्याएं पैदा कर सकती है। जब तक कि यह बहुत आधिकारिक तौर पर सलाह दी जाती है। मैं सभी सामान्य हैक्स / वर्कअराउंड के लिए हूं, लेकिन कन्स्ट्रक्टर एक विशेष रूप से नाजुक विशेषता है और after_initialize एक सीधा विकल्प प्रदान करता है। - mahemoff