पर सेटर ओवरराइड के साथ समस्या यह वास्तव में एक प्रश्न नहीं है, यह एक रिपोर्ट है कि जब मैं एक वस्तु है, तो पर गुण एक वस्तु है, तो मैंने एक समस्या हल की है। मुझे उम्मीद है कि यह एक ही समस्या का सामना करने वाले अन्य लोगों के लिए उपयोगी हो सकता है।ActiveRecord
मुझे एक उदाहरण के साथ स्पष्ट करने दें। मान लीजिए आप दो वर्गों, Book
और Author
है:
class Book < ActiveRecord::Base
belongs_to :author
end
class Author < ActiveRecord::Base
has_many :books
end
बहुत ही सरल। लेकिन, किसी भी कारण से, आपको author
= Book
पर विधि को ओवरराइड करने की आवश्यकता है। चूंकि मैं रेल के लिए नया हूं, मैंने रेल के साथ एग्इल वेब विकास पर सैम रूबी के सुझाव का पालन किया है: attribute_writer
निजी विधि का उपयोग करें। तो, मेरी पहली कोशिश थी:
class Book < ActiveRecord::Base
belongs_to :author
def author=(author)
author = Author.find_or_initialize_by_name(author) if author.is_a? String
self.write_attribute(:author, author)
end
end
दुर्भाग्यवश, यह काम नहीं करता है। यही तो मैं कंसोल से प्राप्त होते हैं:
>> book = Book.new(:name => "Alice's Adventures in Wonderland", :pub_year => 1865)
=> #<Book id: nil, name: "Alice's Adventures in Wonderland", pub_year: 1865, author_id: nil, created_at: nil, updated_at: nil>
>> book.author = "Lewis Carroll"
=> "Lewis Carroll"
>> book
=> #<Book id: nil, name: "Alice's Adventures in Wonderland", pub_year: 1865, author_id: nil, created_at: nil, updated_at: nil>
>> book.author
=> nil
ऐसा लगता है कि रेल यह एक वस्तु है और कुछ भी नहीं करता है नहीं पहचानता है: attribuition के बाद, लेखक अभी भी नहीं के बराबर है! बेशक, मैं write_attribute(:author_id, author.id)
को आजमा सकता हूं, लेकिन यह तब तक मदद नहीं करता जब लेखक अभी तक सहेजा नहीं गया है (इसमें अभी भी कोई आईडी नहीं है!) और मुझे वस्तुओं को एक साथ सहेजने की आवश्यकता है (लेखक को केवल तभी सहेजा जाना चाहिए जब पुस्तक मान्य है)।
एक समाधान के लिए एक बहुत खोज (और व्यर्थ में कई अन्य चीजों की कोशिश) के बाद, मैं इस संदेश मिला: http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/4fe057494c6e23e8, तो अंत में मैं कुछ काम कर कोड था सकता है:
class Book < ActiveRecord::Base
belongs_to :author
def author_with_lookup=(author)
author = Author.find_or_initialize_by_name(author) if author.is_a? String
self.author_without_lookup = author
end
alias_method_chain :author=, :lookup
end
इस बार, सांत्वना था मेरे लिए अच्छा:
>> book = Book.new(:name => "Alice's Adventures in Wonderland", :pub_year => 1865)
=> #<Book id: nil, name: "Alice's Adventures in Wonderland", pub_year: 1865, author_id: nil, created_at: nil, updated_at: nil>
>> book.author = "Lewis Carroll"=> "Lewis Carroll"
>> book
=> #<Book id: nil, name: "Alice's Adventures in Wonderland", pub_year: 1865, author_id: nil, created_at: nil, updated_at: nil>
>> book.author
=> #<Author id: nil, name: "Lewis Carroll", created_at: nil, updated_at: nil>
यहाँ चाल alias_method_chain
, कि एक इंटरसेप्टर और पुराने सेटर (author_without_lookup
) का एक वैकल्पिक नाम (इस मामले author_with_lookup
में) बनाता है। मैं कबूल करता हूं कि इस व्यवस्था को समझने में कुछ समय लगा और मुझे खुशी होगी कि अगर कोई इसे विस्तार से समझाएगा, लेकिन मुझे आश्चर्य हुआ कि इस तरह की समस्या के बारे में जानकारी की कमी क्या थी। मुझे सिर्फ एक पोस्ट खोजने के लिए बहुत कुछ करना है, कि शीर्षक से शुरुआत में समस्या से असंबंधित लग रहा था। मैं रेल के लिए नया हूं, तो आप लोग क्या सोचते हैं: क्या यह एक बुरा अभ्यास है?
मैं इस बनाने के लिए सोचा था कि हल, लेकिन मैं डुप्लिकेट गुण नहीं चाहता था। मैंने जिस विधि का प्रस्ताव दिया है वह बहुत अच्छी तरह से काम कर रहा है; मैं बस इसे साझा करना चाहता था। मैं वास्तव में इसके साथ text_field चाल बना सकता हूं। लेकिन आपके उत्तर के लिए धन्यवाद! = डी –
'author_name' विधि को 'प्रतिनिधि: नाम,: से =>: लेखक,: prefix => true' के साथ प्रतिस्थापित करने के लिए और अधिक सही नहीं होगा? –
@ एडम, यह निश्चित रूप से ऐसा करने का एक वैकल्पिक तरीका है। कई तरीकों से निपटने के दौरान आमतौर पर मैं केवल 'प्रतिनिधि' का उपयोग करता हूं। यदि केवल एक ही है तो मैं विधि को सीधे परिभाषित करना पसंद करता हूं क्योंकि मुझे लगता है कि यह अधिक स्पष्ट है। – ryanb