将多个联接引入一种方法

时间:2018-08-05 17:29:25

标签: ruby-on-rails ruby

我的应用程序中有一个用户,该用户可以具有多个评估,计划和材料。我的数据库中这些之间已经存在关系。我想在一个选项卡中显示所有这些内容,而不必查询数据库太多次。

我试图做一个将它们全部合并到一个表中的方法,但是没有成功。返回是以下错误:undefined method 'joins' for #<User:0x007fcec9e91368>

def library
  self.joins(:materials, :assessments, :plans)
end

我的最终目标是仅对联接返回的所有对象进行编程,以便可以显示它们,而不是需要查询三个不同的变量来减慢加载时间。知道这怎么可能吗?

class User < ApplicationRecord
  has_many :materials, dependent: :destroy
  has_many :plans, dependent: :destroy
  has_many :assessments, dependent: :destroy
end 

class Material < ApplicationRecord
  belongs_to :user
end

class Assessment < ApplicationRecord
  belongs_to :user
end

class Plan < ApplicationRecord
  belongs_to :user
end

2 个答案:

答案 0 :(得分:2)

如果您要做的只是预加载关联,请使用includes

class User < ApplicationRecord
  # ...

  scope :with_library, -> { includes(:materials, :assessments, :plans) }
end

像这样使用它:

User.with_library.find(1)
User.where(:name => "Trenton").with_library
User.all.with_library
# etc.

一旦关联被预加载,您可以将其用于library方法,以使用特定用户的所有材料,评估和计划填充单个阵列:

class User < ApplicationRecord
  # ...

  def library
    [materials, assessments, plans].map(&:to_a).flatten(1)
  end
end

用例示例:

users = User.all.with_library
users.first.library
# => [ ... ]

更多信息:https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

答案 1 :(得分:0)

includes优先于joins,除非您有其他特殊原因。 includes将消除N + 1个查询,同时仍在关联中构造可用的记录:然后,您可以像以往那样遍历所有内容。

但是,在这种情况下,听起来好像您是在单个User实例中工​​作:在这种情况下,includes(或joins)真的无济于事-没有N + 1个查询可以消除。

避免在您要显示的每行(N + 1)上运行查询很重要,但是一个查询和三个查询之间的差异可以忽略不计。 (尝试将所有内容压缩在一起会花费更多的开销。)对于这种用法,这是不必要的。