我正在尝试在Ruby on Rails项目中执行以下操作:
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上的HABTM,我有一个名为food_categories_food_items
的映射表。
我需要做些什么才能让some_food_item.places
通过映射表正确查看位置,而不是在food_item_id
表中查找food_categories
?
答案 0 :(得分:7)
我的第一个答案版本不正确,但这个版本效果很好。我第一次做了一些拼写错误(实际上没有创建应用程序进行测试的危险),但这次我验证了。并且需要一个插件,但这很容易。首先,安装插件:
script/plugin install git://github.com/ianwhite/nested_has_many_through.git
这将安装Ian White的解决方法,并且无缝地工作。现在模型,直接从我设置的测试应用程序复制,以使其工作:
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来详细解释。它甚至在GitHub上有一个附带的示例应用程序来下载和播放。
答案 1 :(得分:2)
几个月前我写了an article about this。简而言之,Rails不允许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
方法。
答案 2 :(得分:1)
我正在使用Rails 3.2.13和Rasmus,你的原始设置现在似乎在HABTM上工作正常。
我建议用户在尝试解决方法之前先尝试。
答案 3 :(得分:-1)
这是正确的,因为你无法在连接表上执行“has many through”。从本质上讲,你试图将关系扩展到比你真正的程度更远的程度。 HABTM(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
注意,我还在“Place - &gt; has_many:food_items”中修正了拼写错误。这应该照顾您的需求,并为您提供额外的好处,即能够在将来为您的FoodCategoryItems“加入”模型添加功能。