I'm using Rails 2, and I have a one-to-many association between the Project
model and the Schedule
model in this app.
I have an observer check when attributes of various things change, and in response, it iterates over an array of hashes with which to populate new Schedule
instances.
Each Schedule
instance should have an attribute, disp_order
, which eventually tells the front end where to display it when showing them in a list. The disp_order
is populated upon adding the schedule to the project, so that it equals one more than the current highest disp_order
.
The problem is in the iteration in the observer. When I iterate over the array of hashes filled with Schedule
data, each time through the iteration should calculate the disp_order
as one higher than the previous one, to account for the Schedule
it just added. However, in practice, it doesn't--unless I refresh the Project
object in the middle of the iteration with project = Project.find(project.id)
, or else it seems always to calculate the same max value of the disp_order
s, and doesn't have an accurate list of those Schedule
instances to go on.
Is there a better way to do this? (Note: I just mean is there a better way so that I don't have to tell project to re-find itself. There are a number of places I'm actively cleaning up the rest of the code which follows, but for this question I'm really only interested in this one line and things that impact it.)
project.rb
class Project < ActiveRecord::Base
# ...
has_many :schedules, :dependent => :destroy
# ...
belongs_to :data, :polymorphic => true, :dependent => :destroy
accepts_nested_attributes_for :data
# ...
schedule.rb
class Schedule < ActiveRecord::Base
belongs_to :project, :include => [:data]
# ...
project_event_observer.rb
class ProjectEventObserver < ActiveRecord::Observer
# ...
def perform_actions(project, actions)
# ...
actions.each { |action|
action.each { |a_type, action_list|
action_list.each { |action_data|
self.send(action_type.to_s.singularize, action_data, project)
project = Project.find(project.id) #My question is about this line.
}
}
}
# ...
sample actions for the iteration above
[
{:add_tasks => [
{:name => "Do a thing", :section => "General"},
{:name => "Do another thing", :section => "General"},
]
},
# More like this one.
]
the observer method that receives the rest of the action data
def add_task(hash, project)
# ...
sched = Schedule.new
hash.each { |key, val|
# ...
sched.write_attribute(key, val)
# ...
}
sched.add_to(project)
end
schedule.rb
def add_to(proj)
schedules = proj.schedules
return if schedules.map(&:name).include?(self.name)
section_tasks = schedules.select{|sched| sched.section == self.section}
if section_tasks.empty?
self.disp_order = 1
else
self.disp_order = section_tasks.map(&:disp_order).max + 1 #always display after previously existing schedules
end
self.project = proj
self.save
end