我正在查询一堆由人们写的和收到的信件。我通过连接表将字母表与人员表相关联,该连接表使用人物类型标识符(0 =创建者,1 =收件人)确定该人是否是相关字母的创建者或收件人。
我的问题:我在一个视图中为用户一次显示50个字母,其中包含可以找到该字母的日期,创建者,收件人和博物馆收藏等信息。页面加载速度非常慢,因为尽管我已经弄清楚如何包括"包括"集合,以便不在显示的每个字母上运行查询,我无法为创建者和收件人执行此操作。如果我只是显示"人们"我也可以做一个包含,但由于我按照他们的角色过滤了人,因此rails在视图中为每个字母运行了几个查询,这需要大约6000毫秒。如果没有创建者和收件人,视图将在大约250毫秒内加载。
以下是我的模型的基础知识:
class ArchiveObject < ActiveRecord::Base
has_many :archive_object_people
has_many :people, :through => :archive_object_people
class ArchiveObjectPerson < ActiveRecord::Base
belongs_to :archive_object
belongs_to :person
class Person < ActiveRecord::Base
has_many :archive_object_people
has_many :archive_objects, :through => :archive_object_people
我还在模型中创建了一些范围和方法来帮助我。 在archive_object.rb中
# These can be used to distinguish recipients from creators of letters
# Use case: ArchiveObject.first.creators
def recipients
people.where("archive_object_people.persontype = '1'")
end
def creators
people.where("archive_object_people.persontype = '0'")
end
scope :recipients, lambda {
joins(:people).where("archive_object_people.persontype = '1'")
}
scope :creators, lambda {
joins(:people).where("archive_object_people.persontype = '0'")
}
我想以我所包含的相同方式预加载创作者和收件人,比如说,字母的位置,以便我可以遍历每个字母并显示letter.title,letter.creators,letter.collection等等。运行几十个查询。例如:ArchiveObject.includes(:collections,:creators)
到目前为止我尝试过的事情。所有这些都会在获取收件人/创建者时运行另一个查询,尽管他们在查看泛型&#34;人员时可能无法运行另一个查询&#34;:
ArchiveObject.joins(:people).where("archive_object_people.persontype = '1'").preload(:people)
ArchiveObject.includes(:people, :archive_object_people).first.recipients
ArchiveObject.includes(:recipients) => raises an exception
我也开始阅读有关重新定义has_many并使用条件仅拉动创建者或收件人的内容,但实际上我需要两个关联,在这种情况下:has_many创建者和has_many收件人。我不知道如何设置它,但如果有人有任何想法,那将是rad。
感谢您提供给我的任何帮助或建议!我很想知道这一点,以便我有一个超级快速和高效的网站。 :)
答案 0 :(得分:1)
好。我花了几个小时但我想出来了!
我删除了所有自定义实用程序方法并重写了一些has_many类型的东西。
class ArchiveObject < ActiveRecord::Base
has_many :archive_object_people
has_many :people, :through => :archive_object_people
has_many :creators, -> { where "archive_object_people.persontype = '0'" },
:through => :archive_object_people
:source => :person
has_many :recipients, -> { where "archive_object_people.persontype = '1'" },
:through => :archive_object_people,
:source => :person
使用模型中的以下内容,您可以执行以下操作:
test = ArchiveObject.includes(:people, :creators, :recipients)
test.first.people # => list of all people on first object
test.first.creators # => list of all people who are creators on first object
test.first.recipients # => all people who are recipients
我之前能够使用我的自定义方法获取该信息,但现在可以预先加载它们,以便它可以预先运行大量查询,然后在为每个字母提取信息时不需要再次重新运行。< / p>
我希望这有助于其他人。请注意:has_many描述中的:source是:person,not:people,这引起了我一些暂时的痛苦。