Rails3 - 多对多关系和范围链
假设我在文章和标签之间有多对多关系
class ArticleTag < ActiveRecord::Base
belongs_to :article
belongs_to :tag
end
class Tag < ActiveRecord::Base
has_many :article_tags
has_many :articles, :through => :article_tags
end
class Article < ActiveRecord::Base
has_many :article_tags
has_many :tags, :through => :article_tags
named_scope :tagged, lambda { |id| joins(:tags).where("tags.id = ?", id) }
end
文章具有标记的范围,正如名称所示,它允许我检索标有特定标签的文章 令
我烦恼的是以下内容:
$ a = Article.create
=> #<Article id: 3, created_at: "2011-05-22 13:54:02", updated_at: "2011-05-22 13:54:02">
$ t1 = Tag.create
=> #<Tag id: 4, created_at: "2011-05-22 13:54:07", updated_at: "2011-05-22 13:54:07">
$ t2 = Tag.create
=> #<Tag id: 5, created_at: "2011-05-22 13:54:11", updated_at: "2011-05-22 13:54:11">
$ a.tags << t1
=> [#<Tag id: 4, created_at: "2011-05-22 13:54:07", updated_at: "2011-05-22 13:54:07">]
$ a.tags << t2
=> [#<Tag id: 4, created_at: "2011-05-22 13:54:07", updated_at: "2011-05-22 13:54:07">, #<Tag id: 5, created_at: "2011-05-22 13:54:11", updated_at: "2011-05-22 13:54:11">]
$ Article.tagged(t1.id)
=> [#<Article id: 3, created_at: "2011-05-22 13:54:02", updated_at: "2011-05-22 13:54:02">]
$ Article.tagged(t2.id)
=> [#<Article id: 3, created_at: "2011-05-22 13:54:02", updated_at: "2011-05-22 13:54:02">]
$ Article.tagged(t1.id).tagged(t2.id)
=> []
如果一篇文章被标记为两个标签,链接相应的范围不允许它的检索。这是应该的行为吗?如果是,我应该如何更改我的代码,以便最后一行不返回空数组?
PS:这里是生成的SQL。
SELECT \"articles\".* FROM \"articles\" INNER JOIN \"article_tags\" ON \"articles\".\"id\" = \"article_tags\".\"article_id\" INNER JOIN \"tags\" ON \"tags\".\"id\" = \"article_tags\".\"tag_id\" WHERE (tags.id = 4) AND (tags.id = 5)
Let's say I have a many_to_many relation ship between Articles and Tags
class ArticleTag < ActiveRecord::Base
belongs_to :article
belongs_to :tag
end
class Tag < ActiveRecord::Base
has_many :article_tags
has_many :articles, :through => :article_tags
end
class Article < ActiveRecord::Base
has_many :article_tags
has_many :tags, :through => :article_tags
named_scope :tagged, lambda { |id| joins(:tags).where("tags.id = ?", id) }
end
Article has the scope tagged, which - as the name says - allows me to retrieve the Articles tagged with a particular tag
What troubles me is the following :
$ a = Article.create
=> #<Article id: 3, created_at: "2011-05-22 13:54:02", updated_at: "2011-05-22 13:54:02">
$ t1 = Tag.create
=> #<Tag id: 4, created_at: "2011-05-22 13:54:07", updated_at: "2011-05-22 13:54:07">
$ t2 = Tag.create
=> #<Tag id: 5, created_at: "2011-05-22 13:54:11", updated_at: "2011-05-22 13:54:11">
$ a.tags << t1
=> [#<Tag id: 4, created_at: "2011-05-22 13:54:07", updated_at: "2011-05-22 13:54:07">]
$ a.tags << t2
=> [#<Tag id: 4, created_at: "2011-05-22 13:54:07", updated_at: "2011-05-22 13:54:07">, #<Tag id: 5, created_at: "2011-05-22 13:54:11", updated_at: "2011-05-22 13:54:11">]
$ Article.tagged(t1.id)
=> [#<Article id: 3, created_at: "2011-05-22 13:54:02", updated_at: "2011-05-22 13:54:02">]
$ Article.tagged(t2.id)
=> [#<Article id: 3, created_at: "2011-05-22 13:54:02", updated_at: "2011-05-22 13:54:02">]
$ Article.tagged(t1.id).tagged(t2.id)
=> []
If an article is tagged with two tags, chaining the corresponding scopes doesn't allow it's retrieval. Is it the supposed behavior? If it is, how should I change my code so that this last line doesn't return an empty array?
PS : here is the generated SQL.
SELECT \"articles\".* FROM \"articles\" INNER JOIN \"article_tags\" ON \"articles\".\"id\" = \"article_tags\".\"article_id\" INNER JOIN \"tags\" ON \"tags\".\"id\" = \"article_tags\".\"tag_id\" WHERE (tags.id = 4) AND (tags.id = 5)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
虽然我不知道为什么内置链接失败,但这里有一个解决方案:
在您的
Article
模型控制台中,您可以调用这些方法:
Although I don't know why the built-in chaining fails, here is a solution:
In your
Article
modelIn console, you can call these methods:
尝试这个
Article.rb 模型中
在控制台的
Try this
In Article.rb model
In console
好的,我找到了解决方案。诀窍是手动创建连接,并在某些地方添加唯一的 id 以避免名称冲突。
Ok, I found a solution. The trick is to manually create the joins, and add an unique id at some places to avoid name conflicts.