问题:我有一个可行的解决方案,但我私下怀疑它可能计算量很大。希望听到任何更有效的方法来实现这一点。
目标:我想按优先级提取书籍的列表,其中该书与学校或班级有多态性关联。
- 学校:有很多课程,通过主题
- 课程:有一个学校,通过主题
- 书籍:可由班级或学校预订
当前类视图文件:
<% @school_class_books.order("priority ASC").each do |book| %>
<b><a href="<%= book.url %>"><%= book.name %></a></b><br />
<%= book.long %><br /><br />
<% end %>
当前class.rb控制器:
@school_class_books = Book.all.where(bookable_type: ["School","Class"],
bookable_id: [@class.school.id,@class.id])
在考虑任何性能问题之前,您应该知道,您编写的代码会因为找到不应该找到的书而导致错误。
例如,如果@school.id
=10和@class.id
=15,则此查询将返回一本书,其可预订字段设置为:bookable_id
=15和bookable_type
="学校"。
那本书属于另一个学派!
这可能更简单:
@books = Book.where(bookable: @school).to_a.concat(Book.where(bookable: @class).to_a)
这是的多态语法糖
@books = Book.where(bookable_type: @school.class.to_s, bookable_id: @school.id).to_a.concat(Book.where(bookable_type: @class.class.to_s, bookable_id: @class.id).to_a)
换句话说,只需进行两次查找并组合结果。
至于性能,使用类似where(my_attribute: [value1, value2, value3])
的语法将生成类似WHERE books.my_attribute IN (value1, value2, value3)
的SQL。
使用IN的SQL语句可能效率低下,因为它们使数据库服务器更难在my_attribute
字段(在本例中为bookable_id
(上使用索引。
最后,您应该考虑将Class
模型重命名为Course
,以避免与Ruby的class
关键字发生名称空间冲突,或者避免程序员在读取变量名时混淆。考虑bookable_type: @class.class.to_s
的尴尬