2010-01-27 24 views
5

bir has_and_belongs_to_many dernek aracılığıyla:Has_many: Ben bir Ruby on Rails projede aşağıdaki yapmaya çalışıyorum

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 

Ama örnek yöntemi some_food_item.places çağırarak bana aşağıdaki hatayı veriyor:

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)) 

Hangi Mükemmel bir anlam ifade eder - FoodItem ve FoodCategory'deki HABTM'ler nedeniyle food_categories_food_items isimli haritalama tablosuna sahibim.

food_categories tablosunda food_item_id ürününü aramak yerine, eşleme tablosundan doğru bir şekilde yerlere bakmak için some_food_item.places almak için ne yapmalıyım?

cevap

6

Cevabın ilk sürümü yanlıştı, ancak bu mükemmel çalışıyor. İlk kez bir çift yazım hatası yaptım (aslında test etmek için bir uygulama yaratma tehlikesi) ama bu kez doğruladım. Ve bir eklentiye ihtiyaç var, ama bu kolay. önce, eklentiyi yükleyin:

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

Bu, Ian White'ın geçici çözümünü yükler ve sorunsuz çalışır.

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 

Şimdi "uzak" dernekler gibi iyi iş: Artık test uygulaması I kurulumu doğrudan kopyalanmış modelleri, bu çalışma almak için. place_instance.food_items ve food_item.places her ikisi de, ilgili basit ilişkilendirmelerin yanı sıra kusursuz şekilde çalışır. Sadece referans için, tüm yabancı anahtarların nereye gittiğini gösteren şema şudur:

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 

Bu yardımcı olur!

GÜNCELLEME: Bu soru birkaç kez yeni geldi. Ayrıntıları açıklamak için bir makale yazdım, nesting your has_many :through relationships. Hatta indirmek ve oynamak için GitHub üzerinde bir örnek uygulama vardır.

+0

Kesinlikle yardımcı olur! Hem çözüm için hem de HABTM'deki kafalar için teşekkür ederiz. Eminim bu çözümü uygulayacağım tek yer olmayacak! –

2

Birkaç ay önce an article about this yazdım. Kısaca, has_and_belongs_to_many arasındaki bir ilişki aracılığıyla has_many numarasına Rails izin verilmez. Ancak, kısmen böyle bir şey yaparak ilişkiyi simüle edebilirsiniz:

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 

Bu Aradığın some_food_item.places yöntemini verecektir.

-1

Bu doğrudur, çünkü birleştirme tablosunda "çok şey vardır" ifadesini uygulayamazsınız. Özünde, ilişkiyi gerçekten yapabileceğinden bir derece daha uzatmaya çalışıyorsun. HABTM (has_and_belongs_to_many) çoğu problem için çok güçlü bir çözüm değildir.

Sizin durumunuzda, FoodCategoryItem adlı bir model eklemenizi ve birleştirme tablonuzu eşleşecek şekilde yeniden adlandırmanızı öneririz. Ayrıca birincil anahtar alanını da eklemeniz gerekecek. Böyle Ardından kurulum modeli dernekler:

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 

Not, ben de "-: food_items> Has_many Yer" bir yazım hatası düzeltildi. Bu, ihtiyacınız olan şeylere dikkat etmeli ve size gelecekte FoodCategoryItems "katıl" modelinize işlevsellik ekleyebilmenin ek avantajını sunmalıdır.

+0

Bunu işe yaratamıyorum - some_food_item.places'ı çağırırken aynı hatayı alıyorum. Görünüşe göre ActiveRecord'da bir sınırlama var (bkz. Http://www.ruby-forum.com/topic/115029). –

+0

Haklısın üzgünüm. Her şeyi düzelten bir cevap ekledim. –

1

Rails 3.2 kullanıyorum.13 ve Rasmus, orijinal kurulumunuz artık HABTM'de iyi çalışıyor gibi görünüyor.

Kullanıcıların bir çözüm bulmaya çalışmadan önce önce denemelerini öneririm.