以下是一个人为的例子,但它会得到重点。
假设我有以下型号。
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Book < ActiveRecord::Base
has_many :chapters
has_many :comments, as: :commentable
end
class Chapter < ActiveRecord::Base
has_many :pages
has_many :comments, as: :commentable
end
class Page < ActiveRecord::Base
has_many :paragraphs
has_many :comments, as: :commentable
end
class Paragraph < ActiveRecord::Base
has_many :comments, as: :commentable
end
可以通过一个查询获取特定图书及其后代的所有评论吗?也就是说,我希望所有评论不仅来自书籍模型,还需要对章节,页面和段落的评论。顺便说一句,我意识到本书可以通过每个模型的关联,为每个模型执行内部联接,但这将导致4个查询。
我使用postgres作为数据库和Rails 3.2.12。
答案 0 :(得分:1)
如果您正在考虑急切加载,可以从Book侧进行,但不能从Comment侧进行。
>> Book.limit(1).includes(:comments).where('comments.id ...') # you'll probably get a book
>> Comment.limit(1).includes(:commentable).where('books.id ...') # you'll get an error
ActiveRecord::EagerLoadPolymorphicError: Can not eagerly load the polymorphic association
您可以随时执行以下操作来获取图书的评论
>> book = Book.first
>> comments = book.comments
>> comments = Comment.where(commentable_type: 'Book', commentable_id: book.id)
答案 1 :(得分:1)
我不知道这是否有帮助,但我正在从数据库方面接近这一点,并试图找出解决这个问题的最佳方法。我认为您的问题将是您的数据库的样子。如果你可以从SQL向后工作,这也可能有所帮助。
这也是一个坚实的数据库设计将使您的生活更轻松的领域。假设我们有以下表结构:
CREATE TABLE node_class (
id int not null unique,
node_type label primary key,
parent_class int references node_class(id)
);
INSERT INTO node_class (id, node_type, parent_class)
VALUES (1, 'book', null), (2, 'chapter', 1), (3, 'page', 2), (4, 'paragraph', 3);
CREATE TABLE book_node (
node_id bigserial primary key,
node_type int not null,
parent_class int,
parent_id int,
.....
foreign key (parent_class, parent_id) references book_node(id, node_type)
foreign key (node_type) references node_class (id),
foreign key (node_type, parent_class) references node_class(id, parent_class)
);
CREATE TABLE book_comments (
id bigserial primary key,
comment_text text not null
);
你可能有其他表然后连接到书籍节点表来提供,例如,章节,页码等。
然后从那里生成一个构建树然后加入注释的查询非常容易:
WITH RECURSIVE bn_tree (node_id, level, path) as
(
SELECT node_id, 1, node_id::text
FROM book_node
where node_id = ?
UNION ALL
SELECT n.node_id, level + 1, path || ',' || n.node_id::text
FROM book_node n
JOIN bn_tree t ON t.node_id = n.parent
)
SELECT c.*
FROM book_comments c
JOIN bn_tree t ON c.node_id = t.node_id;
我认为,一旦您了解了SQL的工作原理,您就可以调整数据库设计,以便更好地使用您的应用程序。