रेल: रेल के साथ has_one एसोसिएशन के साथ बिल्ड का उपयोग करना


143

इस उदाहरण में, मैं एक userनहीं के साथ बनाता हूं profile, फिर बाद में profileउस उपयोगकर्ता के लिए बनाता हूं । मैं एक has_oneसंघ के साथ निर्माण का उपयोग करने की कोशिश की, लेकिन वह उड़ा दिया। जिस तरह से मैं देख रहा हूं कि यह काम कर रहा है has_manyuserकेवल सबसे एक पर है करने के लिए माना जाता है profile

मैं यह कोशिश कर रहा हूं। मेरे पास है:

class User < ActiveRecord::Base
  has_one :profile
end

class Profile < ActiveRecord::Base
  belongs_to :user
end

लेकिन जब मैं करता हूं:

user.build_profile 

मुझे त्रुटि मिली:

ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'profiles.user_id' in 'where clause': SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4)  LIMIT 1

वहाँ रेल में एक रास्ता है 0 या 1 संघ है?


आपने वास्तव में क्या प्रयास किया? क्या आप कृपया, कुछ कोड पोस्ट कर सकते हैं?
जू नोगीरा

जवाबों:


359

buildविधि हस्ताक्षर के लिए अलग है has_oneऔर has_manyसंघों।

class User < ActiveRecord::Base
  has_one :profile
  has_many :messages
end

has_manyएसोसिएशन के लिए बिल्ड सिंटैक्स :

user.messages.build

has_oneएसोसिएशन के लिए बिल्ड सिंटैक्स :

user.build_profile  # this will work

user.profile.build  # this will throw error

अधिक विवरण के लिए has_oneएसोसिएशन प्रलेखन पढ़ें ।


28
हमेशा के लिए has_one के लिए अलग वाक्यविन्यास मुझे पकड़ता है ... अरे!
गैलेक्सी

11
यह मजेदार है कि कैसे शीर्ष रेटेड और स्वीकृत उत्तर यहां ओपी द्वारा पूछे गए एक अलग सवाल का जवाब दे रहा है।
Ajedi32

माना जाता है कि अगर उपयोगकर्ता प्रोफ़ाइल का था (जिसका अर्थ है उपयोगकर्ता तालिका अपनी तालिका में foreign_key PROFILE_ID है) तो भी निर्माण के रूप में यानी ऊपर, लेकिन केवल नए कार्य के लिए उल्लेख किया है उपयोगकर्ता के लिए प्रोफ़ाइल काम करेंगे user.build_profile संपादन के लिए user.build_profile if user.profile.nil? और यदि उपयोगकर्ता बनाने के दौरान तो लिखना आप निर्माण प्रोफ़ाइल करना चाहते हैं accepts_nested_attributes_for :profileइस में उपयोगकर्ता मॉडल। और जिस रूप में उपयोगकर्ता बनाया जा रहा है, उसे लिखें <%= f.simple_fields_for :profile do |p| %>और आगे बढ़ें।
जोश

लेकिन यह अलग व्यवहार has_one या has_many के लिए क्यों रखा गया? डिजाइन करते समय कोई कारण होगा, मुझे लगता है और उम्मीद करते हैं।
जिज्ञासु

@ Ajedi32 जवाब सवाल के शीर्षक से मेल खाता है लेकिन शरीर से नहीं। यह देखते हुए कि यह ( build_<association>) रेल में एक बहुत ही अजीब और अप्रत्याशित व्यवहार है, वास्तविक प्रश्नों की तुलना में इस उत्तर की तलाश में बहुत अधिक लोग हैं, यदि आप जानते हैं कि मेरा क्या मतलब है।
मैक्स विलियम्स

19

त्रुटि संदेश पर एक अच्छी नज़र डालें। यह आपको बता रहा है कि आपको प्रोफ़ाइल तालिकाuser_id में कॉलम की आवश्यकता नहीं है । मॉडल में रिश्तों को सेट करना केवल उत्तर का हिस्सा है।

आपको एक माइग्रेशन बनाने की भी आवश्यकता है जो user_idकॉलम को प्रोफाइल टेबल में जोड़ता है । रेल को उम्मीद है कि यह वहां होगा और यदि यह नहीं है तो आप प्रोफ़ाइल तक नहीं पहुंच सकते।

अधिक जानकारी के लिए कृपया इस लिंक पर एक नज़र डालें:

एसोसिएशन मूल बातें


1
मुझे सिर्फ अपनी समस्या का पता चला। मैं जिस किताब से सीख रहा हूं, उसने विदेशी कुंजी निर्माण को बहुत अच्छी तरह से नहीं समझाया। मैंने एक नया माइग्रेशन बनाया जो मेरे मॉडल में एक विदेशी कुंजी जोड़ता है। धन्यवाद।
espinet

क्या आपको हर बार स्वयं कॉलम बनाने की आवश्यकता है? मेरे पास यह विचार था कि यह स्वचालित रूप से हुआ। मुझे नहीं पता कि मुझे वह विचार कहां से मिला।
रिमियन

आप कमांड लाइन का उपयोग करके एक मॉडल उत्पन्न करते समय कॉलम जोड़ सकते हैं, जैसे कुछ rails g model profile user:references:index address:string bio:text
दुहखो

1

उपयोग के मामले के आधार पर, यह विधि को लपेटने के लिए सुविधाजनक हो सकता है और नहीं मिलने पर स्वचालित रूप से एसोसिएशन का निर्माण कर सकता है।

old_profile = instance_method(:profile)
define_method(:profile) do
  old_profile.bind(self).call || build_profile
end

अब कॉलिंग #profileविधि या तो संबंधित प्रोफ़ाइल को वापस करेगी या एक नया उदाहरण बनाएगी।

स्रोत: जब बंदर एक विधि का उपयोग करता है, तो क्या आप नए कार्यान्वयन से ओवरराइड विधि कह सकते हैं?


1
वर्तमान रेल में (6.0.2.2 पर परीक्षण) आप को यह आसान बनाने के कर सकते हैं: def profile; super || build_profile; end
ग्लासस

-14

यह एक होना चाहिए has_one। यदि buildआप काम नहीं कर रहे हैं, तो आप उपयोग कर सकते हैं new:

ModelName.new( :owner => @owner )

के समान है

@owner.model_names.build

11
यह समान नहीं है: यदि आप बिल्ड के साथ एक नया model_name बनाते हैं, जब @owner सहेजा जाता है तो नया मॉडल_name भी सहेज लिया जाएगा। तो, आप एक माता-पिता और बच्चों को बनाने के लिए बिल्ड का उपयोग कर सकते हैं जो एक साथ सहेजे जाएंगे। यदि आप .new
Max Williams
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.