2010-01-27 16 views
5

मैं एक रूबी ऑन रेल्स परियोजना में निम्न कार्य करने की कोशिश कर रहा हूँ के माध्यम से:has_many: एक has_and_belongs_to_many संघ

class FoodItem < ActiveRecord::Base 
    has_and_belongs_to_many :food_categories 
    has_many :places, :through => :food_categories 
end 

class FoodCategory < ActiveRecord::Base 
    has_and_belongs_to_many :food_items 
    belongs_to :place 
end 

class Place < ActiveRecord::Base 
    has_many :food_categories 
    has_many :food_items, :through => :food_category 
end 

लेकिन उदाहरण विधि some_food_item.places बुला मुझे निम्न त्रुटि देता है:

ActiveRecord::StatementInvalid: PGError: ERROR: column 
food_categories.food_item_id does not exist 
LINE 1: ...laces".id = "food_categories".place_id WHERE (("food_cate... 

: SELECT "places".* FROM "places" INNER JOIN "food_categories" ON "places".id = "food_categories".place_id WHERE (("food_categories".food_item_id = 1)) 

कौन सा सही मायने रखता है - FoodItem और FoodCategory पर एचएबीटीएम की वजह से मेरे पास food_categories_food_items नामक मानचित्रण तालिका है।

तालिका में food_item_id की तलाश करने के बजाय मैपिंग तालिका के माध्यम से सही जगहों को देखने के लिए मुझे some_food_item.places प्राप्त करने के लिए क्या करना है?

उत्तर

6

उत्तर का मेरा पहला संस्करण गलत था, लेकिन यह पूरी तरह से काम करता है। मैंने पहली बार टाइपो (कुछ वास्तव में परीक्षण करने के लिए ऐप नहीं बनाने का खतरा) बनाया लेकिन इस बार मैंने सत्यापित किया। और एक प्लगइन की जरूरत है, लेकिन यह आसान है। पहले, प्लगइन स्थापित:

script/plugin install git://github.com/ianwhite/nested_has_many_through.git 

यह स्थापित करता इयान व्हाइट की वैकल्पिक हल है, और यह सहजता से चलता है।

class FoodItem < ActiveRecord::Base 
    has_many :food_category_items 
    has_many :food_categories, :through => :food_category_items 
    has_many :places, :through => :food_categories 
end 

class FoodCategory < ActiveRecord::Base 
    has_many :food_category_items 
    has_many :food_items, :through => :food_category_items 
    belongs_to :place 
end 

class FoodCategoryItem < ActiveRecord::Base 
    belongs_to :food_item 
    belongs_to :food_category 
end 

class Place < ActiveRecord::Base 
    has_many :food_categories 
    has_many :food_category_items, :through => :food_categories 
    has_many :food_items, :through => :food_category_items 
end 

अब "अब तक" संघों बस के रूप में अच्छी तरह से काम: अब मॉडल, परीक्षण ऐप मैं सेटअप से सीधे कॉपी किया इस काम कर पाने के लिए। place_instance.food_items और food_item.places दोनों काम निर्दोष रूप से, साथ ही सरल सहयोग शामिल हैं। बस में संदर्भ के लिए, यहाँ दिखाने के लिए जहां सभी विदेशी कुंजी जाना मेरी स्कीमा है:

create_table "food_categories", :force => true do |t| 
    t.string "name" 
    t.integer "place_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
end 

create_table "food_category_items", :force => true do |t| 
    t.string "name" 
    t.integer "food_item_id" 
    t.integer "food_category_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
end 

create_table "food_items", :force => true do |t| 
    t.string "name" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
end 

create_table "places", :force => true do |t| 
    t.string "name" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
end 

आशा इस मदद करता है!

अद्यतन: यह प्रश्न हाल ही में कुछ बार आया है। विस्तार से व्याख्या करने के लिए मैंने एक लेख लिखा, nesting your has_many :through relationships। इसमें गिटहब पर डाउनलोड करने और खेलने के लिए एक साथ उदाहरण एप्लिकेशन भी है।

+0

यह निश्चित रूप से मदद करता है! समाधान के लिए और एचएबीटीएम पर सिर के लिए भी धन्यवाद। मुझे यकीन है कि यह एकमात्र जगह नहीं होगी जिसे मैं इस समाधान को लागू करूंगा! –

2

कुछ महीने पहले मैंने an article about this लिखा था। संक्षेप में, has_many रेल द्वारा has_and_belongs_to_many एसोसिएशन की अनुमति नहीं है। हालांकि, अगर आप आंशिक रूप से कुछ इस तरह करने से संबंध अनुकरण कर सकते हैं:

class FoodItem < ActiveRecord::Base 
    has_and_belongs_to_many :food_categories 
    named_scope :in_place, lambda{ |place| 
    { 
     :joins  => :food_categories, 
     :conditions => {:food_categories => {:id => place.food_category_ids}}, 
     :select  => "DISTINCT `food_items`.*" # kill duplicates 
    } 
    } 
end 

class FoodCategory < ActiveRecord::Base 
    has_and_belongs_to_many :food_items 
    belongs_to :place 
end 

class Place 
    has_many :food_categories 
    def food_items 
    FoodItem.in_place(self) 
    end 
end 

यह आपको some_food_item.places विधि आप की तलाश दे देंगे।

-1

यह सही है, क्योंकि आप शामिल तालिका में "कई के माध्यम से" peform नहीं कर सकते हैं। संक्षेप में, आप रिश्ते को एक डिग्री आगे बढ़ाने की कोशिश कर रहे हैं जो आप वास्तव में कर सकते हैं। एचएबीटीएम (has_and_belongs_to_many) ज्यादातर समस्याओं का एक बहुत मजबूत समाधान नहीं है।

आपके मामले में, मैं FoodCategoryItem नामक एक मॉडल जोड़ने और मिलान करने के लिए अपनी जॉइन टेबल का नाम बदलने की अनुशंसा करता हूं। आपको प्राथमिक कुंजी फ़ील्ड को भी वापस जोड़ना होगा। इस तरह तो सेटअप अपने मॉडल संघों:

class FoodItem < ActiveRecord::Base 
    has_many :food_categories, :through => :food_category_items 
    has_many :places, :through => :food_categories 
end 

class FoodCategory < ActiveRecord::Base 
    has_many :food_items, :through => :food_category_items 
    belongs_to :place 
end 

class FoodCategoryItems < ActiveRecord::Base 
    belongs_to :food_item 
    belongs_to :food_category 
end 

class Place < ActiveRecord::Base 
    has_many :food_categories 
    has_many :food_items, :through => :food_categories 
end 

ध्यान दें, मैं भी "-: food_items> has_many प्लेस" लिखने में कोई गलती तय की। आपको अपनी ज़रूरतों का ख्याल रखना चाहिए, और भविष्य में अपने खाद्य श्रेणी में "जुड़ने" मॉडल में कार्यक्षमता जोड़ने में सक्षम होने का अतिरिक्त बोनस देना चाहिए।

+0

मैं इसे काम नहीं कर सकता - कुछ_food_item.places को कॉल करते समय मुझे एक ही त्रुटि मिलती है। यह स्पष्ट रूप से ActiveRecord में एक सीमा है (देखें http://www.ruby-forum.com/topic/115029)। –

+0

आप सही हैं, क्षमा करें। मैंने एक उत्तर जोड़ा जो सबकुछ ठीक करता है। –

1

मैं रेल 3.2 का उपयोग कर रहा हूं।13 और रasmस, आपका मूल सेटअप अब एक एचएबीटीएम पर ठीक काम करता प्रतीत होता है।

मैं सुझाव देता हूं कि उपयोगकर्ता कामकाज करने से पहले पहले प्रयास करें।

संबंधित मुद्दे