如何在递归方法中使用预加载的集合

gab*_*lal 7 ruby activerecord ruby-on-rails ruby-on-rails-4

我有以下自我指涉关联:

class Action < ActiveRecord::Base
  # self referential association
  has_many :action_parents
  has_many :parents, through: :action_parents
  has_many :action_children, class_name: 'ActionParent', foreign_key: 'parent_id'
  has_many :children, through: :action_children, source: :action
  …
  def should_finish
    should_start + duration
  end

  def should_start
    # my_start is a field in db: if there are no parents (root) it will use this field
    return my_start if parents.empty?
    parents.map(&:should_finish).sort.last
  end
end
Run Code Online (Sandbox Code Playgroud)

我的问题是这样的事实,should_finish并且should_start正在相互呼叫,即使我预先加载父母,它也会导致许多查询:

Action.includes(:parents).last.should_finish
# a new query every time it checks for parents
Run Code Online (Sandbox Code Playgroud)

如何高速缓存的任何想法actionsparents

编辑 - 让我给出一些背景信息:

# actions table:        actions_parents table:
# id | duration         task_id | parent_id
# 1  | 5                2       | 1
# 2  | 10               3       | 1
# 3  | 20               4       | 2
# 4  | 15               4       | 3
#
#                      |--------------|
#                      | action 2     |
#         |---------- >| duration: 10 |
#         |            |--------------|
#         |                     |
#  |--------------|             |--------->|--------------|
#  | action 1     |                        | action 4     |
#  | duration: 5  |                        | duration: 15 |
#  |--------------|             |--------->|--------------|
#         |                     |
#         |            |--------------|
#         |----------->| action 3     |
#                      | duration: 20 |
#                      |--------------|
Run Code Online (Sandbox Code Playgroud)

PS:没有循环依赖.

假设我有一个树my_startsome day at 10:00:00:

# action | should_start | should_finish
# -------------------------------------
# 1      | 10:00:00*    | 10:00:05
# 2      | 10:00:05     | 10:00:15
# 3      | 10:00:05     | 10:00:25
# 4      | 10:00:25**   | 10:00:40
#
# * value from db since there is no parent
# ** should_finish of parent with latest should_finish (action 3)
Run Code Online (Sandbox Code Playgroud)

我认为它可以预先加载所有动作 Action.includes(:parents)

Aus*_*tio 0

你尝试过记住这个吗?

模型中

def should_start
  return my_start if parents.empty?

  @should_start ||= parents.map(&:should_finish).sort.last
end
Run Code Online (Sandbox Code Playgroud)