我有一个像这样的数据模型:
# columns include collection_item_id, collection_id, item_id, position, etc
class CollectionItem < ActiveRecord::Base
self.primary_key = 'collection_item_id'
belongs_to :collection
belongs_to :item
end
class Item < ActiveRecord::Base
has_many :collection_items
has_many :collections, :through => :collection_items, :source => :collection
end
class Collection < ActiveRecord::Base
has_many :collection_items, :order => :position
has_many :items, :through => :collection_items, :source => :item, :order => :position
end
一个Item可以出现在多个集合中,也可以在不同位置的同一个集合中出现多次。
我正在尝试创建一个帮助器方法,该方法创建一个菜单,其中包含每个集合中的每个项目。我想使用collection_item_id来跟踪请求之间当前选择的项目,但我无法通过Item类访问连接模型的任何属性。
def helper_method( collection_id )
colls = Collection.find :all
colls.each do |coll|
coll.items.each do |item|
# !!! FAILS HERE ( undefined method `collection_item_id' )
do_something_with( item.collection_item_id )
end
end
end
我也尝试了这个,但它也失败了(未定义的方法`collection_item')
do_something_with( item.collection_item.collection_item_id )
编辑:感谢serioys sam指出上面显然是错误的
我还尝试访问连接模型中的其他属性,如下所示:
do_something_with( item.position )
和
do_something_with( item.collection_item.position )
编辑:感谢serioys sam指出上面显然是错误的
但他们也失败了。
有人可以建议我如何处理这个问题吗?
修改:--------------------&gt;
我从在线文档中发现,使用has_and_belongs_to_many会将连接表属性附加到已检索的项目,但显然已弃用。我还没有尝试过。
目前我正在修改我的Collection模型,如下所示:
class Collection < ActiveRecord::Base
has_many :collection_items, :order => :position, :include => :item
...
end
并更改帮助程序以使用coll.collection_items而不是coll.items
修改:--------------------&gt;
我已经改变了我的帮手,如上所述工作并且工作正常 - (谢谢你)
这使我的代码变得一团糟 - 因为其他因素在这里没有详细说明 - 但是重新分解的一两个小时都不会解决。
答案 0 :(得分:3)
在您的示例中,您已在Item模型关系中为collection_items和collections定义了has_many,生成的关联方法分别是collection_items和collections,它们都返回一个数组,因此您尝试访问此处的方式是错误的。这主要是对很多人的关系。只需查看此Asscociation Documentation以获取进一步参考。
答案 1 :(得分:3)
do_something_with( item.collection_item_id )
此操作失败,因为item没有collection_item_id成员。
do_something_with( item.collection_item.collection_item_id )
此操作失败,因为item没有collection_item成员。
请记住item和collection_items之间的关系是has_many。因此,item具有collection_items,而不仅仅是单个项目。此外,每个集合都有一个集合项列表。你想做的可能就是:
colls = Collection.find :all
colls.each do |coll|
coll.collection_items.each do |collection_item|
do_something_with( collection_item.id )
end
end
其他一些建议:
我从在线文档中发现,使用has_and_belongs_to_many会将连接表属性附加到已检索的项目,但显然已弃用。我还没有尝试过。
我建议你坚持使用has_many:through,因为has_and_belongs_to_many更令人困惑,并没有提供任何真正的好处。
答案 2 :(得分:0)
我能够为我的一个模特工作:
class Group < ActiveRecord::Base
has_many :users, :through => :memberships, :source => :user do
def with_join
proxy_target.map do |user|
proxy_owner = proxy_owner()
user.metaclass.send(:define_method, :membership) do
memberships.detect {|_| _.group == proxy_owner}
end
user
end
end
end
end
在你的情况下,这样的事情应该有效(未经测试):
class Collection < ActiveRecord::Base
has_many :collection_items, :order => :position
has_many :items, :through => :collection_items, :source => :item, :order => :position do
def with_join
proxy_target.map do |items|
proxy_owner = proxy_owner()
item.metaclass.send(:define_method, :join) do
collection_items.detect {|_| _.collection == proxy_owner}
end
item
end
end
end
end
现在只要您访问这样的项目(items.with_join
),就可以从项目中访问CollectionItem:
def helper_method( collection_id )
colls = Collection.find :all
colls.each do |coll|
coll.items.with_join.each do |item|
do_something_with( item.join.collection_item_id )
end
end
end
这是一个更通用的解决方案,您可以使用它将此行为添加到任何has_many :through
关联:
http://github.com/TylerRick/has_many_through_with_join_model
class Collection < ActiveRecord::Base
has_many :collection_items, :order => :position
has_many :items, :through => :collection_items, :source => :item, :order => :position, :extend => WithJoinModel
end