Question

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

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top