在这种情况下如何急切加载?

时间:2013-04-01 12:02:25

标签: ruby-on-rails activerecord associations eager-loading ruby-on-rails-4

class Model RunningTracks < ActiveRecord::Base
  has_many :achievements
  has_many :runners, through: :achievements

class Model Runner < ActiveRecord::Base
  has_many :achievements
  has_many :running_tracks, through: :achievements

class Model Achievement < ActiveRecord::Base
  belongs_to :runner
  belongs_to :running_tracks

在HomePage上有一个each do列表,用于显示所有RunningTracks。在轨道旁边,我们会显示一个按钮,将其标记为运行。在控制器的查询中,一个急切的加载解决方案是includesreferences(Rails 4):

class RunningTracksController
  def index
    @running_tracks = RunningTracks.includes(:achievements).references(:achievements)
  end

为了提高可用性,如果已经标记了每个记录旁边的按钮,则该按钮不应该是可见的。 (将以辅助方法重构)

@running_tracks.each do |track|
  .
  - unless track.achievements.map(&:user_id).include? current_user.id
    = button_to "done", running_track_mark_as_done_path(track)

这有效......但是......随着数据库获取更多记录,它将查询大量成就,因此只对includes的成就进行自定义关联和current_user查询(设计应该是解决方案。

class Model RunningTracks < ActiveRecord::Base
  .
  has_many :achieved_runns, -> { where user_id: current_user.id }, class_name "Achievement"

但是因为在模型中无法访问current_user,所以这不起作用。我不认为可以将变量传递给hay_many关联,是吗?

是否有一个更有效的解决方案来加载所有 RunningTracks,包括当前用户的成就? 谢谢你宝贵的时间!

1 个答案:

答案 0 :(得分:1)

以下是丑陋的并打破了ActiveRecord的比喻,但随着DB的大小增加,它会给你非常快速的查找。也许其他人可以通过一种方式将其保持在渴望加载的范例中。

class RunningTrack
   # Returns a Set (for fast lookups) of track IDs that have at least one achievement for the provided user
   def self.running_track_ids_for_achievements_for_user(user_id)
      Set.new Achievement.where(:user_id => user_id).pluck(:running_track_id)
   end
end

然后在你的控制器中:

class RunningTracksController
   def index
      @running_tracks = RunningTracks.all
      @running_track_ids_for_achievements_for_user = RunningTrack.running_track_ids_for_achievements_for_user(current_user.id)
   end
end

您的观点:

- unless @running_track_ids_with_achievements_for_user.include? track
   = button_to "done", running_track_mark_as_done_path(track)