I have two models, Forums and Topics, Forums has many Topics. Each has an active boolean. When I flip the active flag on a Forum, I want its Topics to all get their flag flipped as well. My thought was to do this in a before_save def before_save unless self.active? self.topics.each{|topic| topic.close} end
In Topic, I have defined the close method: def close self.active = false self.save end
Am I taking the wrong approach here (should I be doing is elsewhere, like in a controller?) I don't get any errors, but nothing happens when I set the flag to false (I don't necessarily want to flip all of the topics to active when setting the forum to active, so I only need this to go one way).
Thanks
Nope, you've got the right approach, you just need a slight nudge. See example below.
class Forum < ActiveRecord::Base
has_many :topics
after_save :close_topics!
def close!
self.active = false
self.save!
end
private
def close_topics!
self.topics.each(&:close!) unless self.active
end
end
class Topic < ActiveRecord::Base
belongs_to :forum
def close!
self.active = false
self.save!
end
end
You can also use an ActiveRecord Observer. I personally prefer this over a filter as you are decoupling your classes more this way. And I tend to like proper separation of concerns, so..
# rails generate observer Forum
class ForumObserver < ActiveRecord::Observer
def after_save (forum)
forum.topics.each(&:close!) unless forum.active
end
end
I'm assuming once these records are deactivated, they will not become active ever again. Regardless, however, the code for additional functionality to handle the opposite case is negligible.
P.S. If you're not familiar with the &:handler
syntax, it's simply a shortcut for mapping to function or variable per item in an enumerable.