【问题标题】:How to eager load in this case?在这种情况下如何急切加载?
【发布时间】:2013-04-01 12:02:24
【问题描述】:
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

在主页上有一个each do 列表来显示所有 RunningTrack。在轨道旁边,我们显示一个按钮,将其标记为运行。急切的加载解决方案是控制器查询中的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 关联,是吗?

是否有更有效的解决方案来预先加载所有 RunningTrack,包括当前用户的成就? 感谢您宝贵的时间!

【问题讨论】:

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


    【解决方案1】:

    以下内容很丑陋并且打破了 ActiveRecord 的比喻,但随着数据库的增长,您可以快速查找。也许其他人可以通过一种方法将其保持在急切加载范式中。

    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)
    

    【讨论】:

    • 感谢您的回答。这是我尝试过的一种解决方案。但我想列出所有 RunningTracks。不幸的是,这将仅列出对 current_user 有成就的 RunningTrack。到目前为止,唯一的解决方法是自定义has_many :user_achievements, -&gt; where user_id "1", class_name: "Achievement。然后执行RunningTracks.user_achievements.explain 并检索 sql 查询。然后我做了一个 find_by_sql 并粘贴了与 current_user 交换用户 ID 的 sql 查询。不幸的是,这个解决方案是有缺陷的,但只要只有一个成就/轨道就可以工作。
    • 好的,我是否正确理解您想要所有 RunningTrack,但它们的“成就”关联只能填充 user_id 等于 current_user.id 的成就?
    • 是的,就像我在控制台中所做的那样:RunningTracks.includes(:user_achievements).references(:user_achievements) 完全符合我的要求,除了我需要在模型中指定用户 ID。但是我无法访问 current_user。
    • 实际上,我正在研究的过滤 LEFT OUTER JOIN 的想法行不通,我将不得不继续考虑这一点。
    • 这种情况下,你是不是只用成就关联来查询当前用户有没有?只要您不需要Achievement 中的其他数据,我就有一个快速批量查找的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 2020-04-17
    • 1970-01-01
    • 2016-09-27
    相关资源
    最近更新 更多