Reputation: 728
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.)
class Project < ActiveRecord::Base
# ...
has_many :schedules, :dependent => :destroy
# ...
belongs_to :data, :polymorphic => true, :dependent => :destroy
accepts_nested_attributes_for :data
# ...
class Schedule < ActiveRecord::Base
belongs_to :project, :include => [:data]
# ...
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.
}
}
}
# ...
[
{: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
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
Upvotes: 4
Views: 1104
Reputation: 3433
You're running into this issue because you're working off of a in-memory cached object.
Take a look at the association documentation.
You can pass the argument of true in your Schedule model's add_to function to reload the query.
Other options would include inverse_of but that's not available to you because you're using polymorphic associations, as per the docs.
Upvotes: 3