Search code examples
ruby-on-railscallbackassociationsafter-savebefore-save

Rails - Trying to flip an active flag in children associations


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


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.