8

मैं ActiveRecord में कुछ कस्टम विधियों को जोड़ने का प्रयास कर रहा हूं। मैं एक मॉडल के हर date क्षेत्र के लिए एक *_after और *_before स्कोप जोड़ना चाहते हैं तो मैं कुछ इस तरह कर सकते हैं:विस्तारित ActiveRecord :: बेस

User.created_at_after(DateTime.now - 3.days).created_at_before(DateTime.now) 

मैं यहाँ समाधान समझाया Rails extending ActiveRecord::Base का पालन किया है लेकिन जब मैं रेल सांत्वना निष्पादित और करने की कोशिश उन तरीकों को कॉल करें जिन्हें मुझे undefined method त्रुटि मिलती है।

# config/initializers/active_record_date_extension.rb 
require "active_record_date_extension" 

# lib/active_record_date_extension.rb 
module ActiveRecordDateExtension 
    extend ActiveSupport::Concern 

    included do |base| 
    base.columns_hash.each do |column_name,column| 
     if ["datetime","date"].include? column.type 
     base.define_method("#{column_name}_after") do |date| 
      where("#{column_name} > ?", date) 
     end 
     base.define_method("#{column_name}_before") do |date| 
      where("#{column_name} < ?", date) 
     end 
     end 
    end 
    end 
end 
Rails.application.eager_load! 

ActiveRecord::Base.descendants.each do |model| 
    model.send(:include, ActiveRecordDateExtension) 
end 

क्या मैं गलत कर रहा हूँ:

यहाँ मेरी कोड है?

+0

क्या आपको स्टैक ट्रेस पोस्ट करना दिमाग है? साथ ही 'ActiveRecordDateExtension.instance_methods' के परिणाम भी? –

+0

@ जेरेमीरोडी रेल कंसोल सामान्य रूप से चलता है। अपरिभाषित विधि 'created_at_before' # के लिए <वर्ग:: 0x007fb500970b00> यहाँ .... मैं एक 'अपरिभाषित method' त्रुटि जब मैं फोन करने की कोशिश उदाहरण के लिए,' User.created_at_before (DateTime.now) ' NoMethodError मिलता है, 'instance_methods' और 'विधियों' के लिए आउटपुट है। लेकिन ध्यान रखें कि मैं कक्षा विधियों को परिभाषित करने की कोशिश कर रहा हूं। 'ActiveRecordDateExtension.instance_methods => []' 'ActiveRecordDateExtension.methods (false) => []' –

उत्तर

1

पिछले जवाब मैं समस्याओं का हिस्सा महसूस किया के लिए धन्यवाद है।

  1. column.type एक प्रतीक है और मैं एक स्ट्रिंग से तुलना किया गया था: यहाँ सभी समस्याओं और समाधान है कि मैं कुछ शोध के बाद करने के लिए आया था।
  2. base.define_method एक निजी विधि
  3. मैं base वर्ग है और न ही class में नहीं, singleton_class में पद्धतियां निर्धारित करने के लिए किया था है।
  4. Rails.application.eager_load! जब आवश्यक नहीं है तब भी उत्सुक भार का कारण बन जाएगा। यह कार्यक्षमता को प्रभावित नहीं कर रहा था लेकिन पहले स्थान पर उत्सुक भार इस "विस्तार" की ज़िम्मेदारी नहीं होना चाहिए और दूसरी जगह यह रेल में निर्भर करता है, जिससे "एक्सटेंशन" केवल रेल संगत हो जाता है।

खाते में इन समस्याओं को मैं रूबी की method_missing कार्यक्षमता का उपयोग यह लागू करने का फैसला लेते हुए और मैं इस मणि (https://github.com/simon0191/date_supercharger) लिखा था। इस प्रश्न के लिए यहां प्रासंगिक भाग दिया गया है:

module DateSupercharger 
    extend ActiveSupport::Concern 

    included do 
    def self.method_missing(method_sym, *arguments, &block) 
     return super unless descends_from_active_record? 
     matcher = Matcher.new(self,method_sym) 
     # Inside matcher 
     # method_sym.to_s =~ /^(.+)_(before|after)$/ 

     if matcher.match? 
     method_definer = MethodDefiner.new(self) # self will be klass inside Matcher 
     method_definer.define(attribute: matcher.attribute, suffix: matcher.suffix) 
     # Inside MethodDefiner 
     # new_method = "#{attribute}_#{suffix}" 
     # operators = { after: ">", before: "<" } 
     # klass.singleton_class.class_eval do 
     # define_method(new_method) do |date| 
     #  where("#{attribute} #{operators[suffix]} ?", date) 
     # end 
     # end 
     send(method_sym, *arguments) 
     else 
     super 
     end 
    end 

    def self.respond_to?(method_sym, include_private = false) 
     return super unless descends_from_active_record? 
     if Matcher.new(self,method_sym).match? 
     true 
     else 
     super 
     end 
    end 
    end 
end 
ActiveRecord::Base.send :include, DateSupercharger 
3

रेल 4.1.9 और रूबी 2.2.1 का उपयोग करके, मैंने ऊपर दिए गए कोड के साथ कुछ मुद्दों को देखा।

  1. आप तार के साथ column.type तुलना कर रहे हैं, और रेल उस विशेषता के लिए प्रतीकों देता है।
  2. base.define_method एक निजी विधि कॉल करने के प्रयास कर रहा है, आप के आसपास मिल सकती है कि send

साथ इस ट्वीक कोड

module ActiveRecordDateExtension 
    extend ActiveSupport::Concern 

    included do |base| 
    base.columns_hash.each do |column_name,column|  
     if [:datetime, :date].include? column.type    
     base.class.send(:define_method, "#{column_name}_after") do |date| 
      where("#{column_name} > ?", date) 
     end 
     base.class.send(:define_method, "#{column_name}_before") do |date| 
      where("#{column_name} < ?", date) 
     end 
     end 
    end 
    end 
end 
+0

'बेस' क्लास की आवश्यकता क्यों है 'बेस'? 'base.class' का उपयोग करने में कोई समस्या है: प्रत्येक वर्ग में अब विधियां हैं।क्या इससे बचने का कोई तरीका है, और केवल ActiveRecord :: बेस वंशजों के लिए उन विधियों को परिभाषित करें? –

+0

मेरा मानना ​​है कि आप 'User.created_at_after' चाहते थे, सही? इसलिए यही कारण है कि 'base.class' होना चाहिए जहां आप विधि को परिभाषित करते हैं। यदि आप इसे 'आधार' पर परिभाषित करते हैं, तो यह क्लास विधि के बजाय एक उदाहरण विधि बन जाता है। – yez