2
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显示所有 RunningTrack 的列表。在轨道旁边,我们显示一个按钮,将其标记为运行。急切加载解决方案是控制器查询中的includesand (Rails 4):references

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,包括当前用户的成就感谢您宝贵的时间!

4

1 回答 1

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)
于 2013-04-02T18:03:15.090 回答