获取 Rails 中某个模型类型的所有记录的所有关联数据?

dei*_*tch 5 ruby-on-rails ruby-on-rails-4

如何将给定模型的所有记录的所有关联数据融合在一起?

我有以下型号:

User --N:1--> Reservation <--1:N-- Concert
Run Code Online (Sandbox Code Playgroud)

所以伪代码:

Reservation belongs_to User
Reservation belongs_to Concert
User has_many Reservations
User has_many Concerts through Reservations
Concert has_many Reservations
Concert has_many Users through Reservations
Run Code Online (Sandbox Code Playgroud)

我如何制作一个包含所有内容的大数组?

  • 我可以通过以下方式获得所有预订 Reservation.all
  • 我可以通过以下方式获取特定预订的用户 Reservation.find(25).user
  • 我可以通过以下方式获得特定预订的音乐会 Reservation.find(25).concert

但是我如何为所有人获得它?如果我做

Reservation.all.each do |res|
   res.user.name+","+res.concert.name+","+res.concert.date # etc.
end
Run Code Online (Sandbox Code Playgroud)

然后它将在循环时为每个预订执行两个新的数据库查询。对于 10 条记录,这可能无关紧要,但对于数千条记录,可能会非常痛苦。添加其他关联(例如音乐会所属场地、用户拥有_一个电子邮件等)...

有什么办法可以说“获取所有预订和以下附加信息”,以便在单个 SQL 查询中加载?

Dre*_*nmi 4

您想要完成的任务称为“立即加载”,可以使用includesin 来完成ActiveRecord。见下文:

N+1查询问题

Active Record 允许您提前指定要加载的所有关联。这可以通过指定 Model.find 调用的 contains 方法来实现。通过包含,Active Record 可确保使用尽可能少的查询来加载所有指定的关联。

http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

在您的示例中,您可以使用以下内容:

Reservation.all.includes(:user, :concert)
Run Code Online (Sandbox Code Playgroud)

:inverse_of为您的关系指定选项也是一个好主意:belongs_to。这优化了对象加载并确保交叉引用模型将指向内存中的同一对象,即:

@user == @user.reservations.first.user # true
Run Code Online (Sandbox Code Playgroud)

更多信息请参见此处:

如果您在连接模型上使用belongs_to,最好在belongs_to上设置:inverse_of选项...

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

在你的例子中:

# app/models/reservation.rb

belongs_to :user, :inverse_of => :reservations
belongs_to :concert, :inverse_of => :reservations
Run Code Online (Sandbox Code Playgroud)