I've the following self referential association:
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
My problem is the fact that should_finish
and should_start
are calling each other and even if I preload the parents it keeps resulting in many queries:
Action.includes(:parents).last.should_finish
# a new query every time it checks for parents
Any idea on how to cache actions
and parents
?
EDIT - let me give some context:
# 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 |
# |--------------|
PS: there are no circular dependencies.
Assuming I have a tree my_start
field of some 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)
I thought it could preload all actions using Action.includes(:parents)