5

में अनुपलब्ध विधि का उपयोग करना मेरे पास कई दिनांक विशेषताओं वाला मॉडल है। मैं स्ट्रिंग्स के रूप में मान सेट करने और प्राप्त करने में सक्षम होना चाहता हूं। मैं अति-रोडे विधियों (bill_date) ताकि तरह से एक:रेल

def bill_date_human 
    date = self.bill_date || Date.today 
    date.strftime('%b %d, %Y') 
    end 
    def bill_date_human=(date_string) 
    self.bill_date = Date.strptime(date_string, '%b %d, %Y') 
    end 

यह मेरी जरूरतों के लिए महान प्रदर्शन करती है, लेकिन मैं कई अन्य तारीख विशेषताओं के लिए एक ही बात करना चाहता हूँ ... मैं कैसे का लाभ ले जाएगा विधि गायब है ताकि किसी भी दिनांक विशेषता को सेट/प्राप्त किया जा सके?

+1

'method_missing' आपको जो अंतिम स्ट्रॉ लेना चाहिए, उसके बारे में है। असल में परिभाषित विधियां बहुत साफ होती हैं, चिंताओं को स्पष्ट अलगाव के साथ बेहतर कोड डिज़ाइन की ओर ले जाती हैं, समझने और तेज़ी से समझना बहुत आसान है। तो यदि आप अपनी विधियों को परिभाषित कर सकते हैं, तो आपको हमेशा यह करना चाहिए। –

+0

जैसा कि केएल -7 से सीखा गया है, method_missing की तुलना में बेहतर दृष्टिकोण हैं, लेकिन इस मॉडल के लिए मेरे पास 4 अलग-अलग दिनांक विशेषताएं हैं, मैन्युअल रूप से प्रत्येक को परिभाषित करना समाधान नहीं है। DRY – tybro0103

+0

ठीक है, केएल -7 की विधि वास्तव में यहां पसंदीदा है। क्योंकि वह वास्तव में जो भी मेरा मतलब है उसका प्रस्ताव दे रहा है: विधियों को परिभाषित करें। –

उत्तर

10

जैसा कि आप पहले से ही वांछित तरीकों के हस्ताक्षर को जानते हैं, method_missing का उपयोग करने के बजाय उन्हें परिभाषित करना बेहतर हो सकता है। आपको लगता है कि जैसे यह कर सकते हैं (आप वर्ग परिभाषा के अंदर):

[:bill_date, :registration_date, :some_other_date].each do |attr| 
    define_method("#{attr}_human") do 
    (send(attr) || Date.today).strftime('%b %d, %Y') 
    end 

    define_method("#{attr}_human=") do |date_string| 
    self.send "#{attr}=", Date.strptime(date_string, '%b %d, %Y') 
    end 
end 

यदि सब तारीख विशेषताओं लिस्टिंग एक समस्या इस दृष्टिकोण बेहतर है के रूप में आप method_missing अंदर कुछ जादू के बजाय नियमित तरीकों के साथ काम कर रहे हैं नहीं है।

आप सभी विशेषताओं है कि _date के साथ समाप्त होने के नाम करने के लिए कि लागू करना चाहते हैं तो आप उस तरह उन्हें प्राप्त कर सकते हैं (अपने वर्ग परिभाषा के अंदर):

column_names.grep(/_date$/) 

और यहाँ, method_missing समाधान (परीक्षण नहीं किया है, हालांकि पिछले एक या तो परीक्षण नहीं किया है):

def method_missing(method_name, *args, &block) 
    # delegate to superclass if you're not handling that method_name 
    return super unless /^(.*)_date(=?)/ =~ method_name 

    # after match we have attribute name in $1 captured group and '' or '=' in $2 
    if $2.blank? 
    (send($1) || Date.today).strftime('%b %d, %Y') 
    else 
    self.send "#{$1}=", Date.strptime(args[0], '%b %d, %Y') 
    end 
end 

इसके अलावा यह respond_to? विधि ओवरराइड और विधि के नाम के लिए true वापस जाने के लिए अच्छा है, कि तुम अंदर संभाल method_missing (1.9 में आपको इसके बजाय respond_to_missing? ओवरराइड करना चाहिए)।

+0

ओउओ अच्छा! मैं पहले define_method में नहीं आया था :) मैं अभी भी अनुपलब्ध कार्यान्वयन विधि को देखना चाहता हूं, लेकिन बेहतर समाधान – tybro0103

+1

के लिए +1 जोड़ा गया 'method_missing' संस्करण', लेकिन यदि आप इन विधियों को परिभाषित कर सकते हैं तो इसका उपयोग न करें। –

+1

@ केएल -7 आपकी 'method_missing' में विधि को संभालने पर आपको सीधे सुपर के साथ वापस जाना चाहिए। अभी, नीचे दिए गए विशेषता को हमेशा निष्पादित किया जाता है। –

5

आपको एक्टिवमोडेल के AttributeMethods मॉड्यूल (जो सक्रिय रिकॉर्ड पहले से ही सामान के समूह के लिए उपयोग करता है) में रुचि हो सकती है, जो आपको चाहिए (लेकिन बिल्कुल नहीं) जो आपको चाहिए।

संक्षेप में आप करने के बाद यह किया, my_instance.bill_date_human 'bill_date' के लिए ATTR_NAME सेट के साथ attribute_human कहेंगे

class MyModel < ActiveRecord::Base 

    attribute_method_suffix '_human' 

    def attribute_human(attr_name) 
    date = self.send(attr_name) || Date.today 
    date.strftime('%b %d, %Y') 
    end 
end 

ऐसा करने में सक्षम होना चाहिए। ActiveModel आपके लिए method_missing, respond_to जैसी चीज़ों को संभाल लेगा। केवल नकारात्मक पक्ष यह है कि सभी स्तंभों के लिए ये _ ह्यूमन विधियां मौजूद होंगी।