I use Rails 2 and I have a one-to-many association between the model Projectand the model Schedulein this application.
I have an observer check when the attributes of different things change, and in response, it iterates over an array of hashes with which you can fill in new instances Schedule.
Each instance Schedulemust have an attribute disp_orderthat ultimately tells the front end where to display it, showing them in a list. disp_orderIt is filled by adding a schedule to the project, so that it is equal to one greater than the current one disp_order.
The problem is iteration in the observer. When I Scheduleiterate over an array of hashes filled with data , each time through iteration I should calculate disp_orderas one higher than the previous one to account for the added one Schedule. However, in practice this is not the case if I do not update the object Projectin the middle of the iteration with project = Project.find(project.id), otherwise the same maximum value disp_orders is computed all the same and not executed. You have an exact list of these Scheduleinstances.
Is there a better way to do this? (Note: I mean, there is a better way so that I cannot say that the project will find itself again. There are several places in which I actively clear the rest of the code that follows, but there is a question for this. I am only interested in this line and everything that affects 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)
}
}
}
[
{:add_tasks => [
{:name => "Do a thing", :section => "General"},
{:name => "Do another thing", :section => "General"},
]
},
# More like this one.
]
,
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
end
self.project = proj
self.save
end