Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save joelbiffin/001d19d70a1d519ab64320b440c2477f to your computer and use it in GitHub Desktop.
Save joelbiffin/001d19d70a1d519ab64320b440c2477f to your computer and use it in GitHub Desktop.

Decoupling Models from their V1 'after actions'

The idea would be to remove all the after_create / after_update hooks in our Active Record models and replace them with created_{ModelName} / updated_{ModelName} events containing the new model attributes.

For example

class User < ApplicationRecord
  after_create :set_collaboration
  after_create :add_interests
  after_create :create_stat_record

  after_update :admin_chat_to_do
  after_update :create_stat_record
end

would become

class User < ApplicationRecord
  after_create :publish_created_user_event
  after_update :publish_updated_user_event

  def publish_created_user_event
    publish_user_event(save_mode: "created") 
  end
  
  def publish_updated_user_event
    publish_user_event(save_mode: "updated")
  end

  def publish_user_event(save_mode:)
    EventClient.publish(
      topic: "#{save_mode}_user",
      data: self.attributes,
    )
  end
end

The next stage of the implementation would be to invert the dependencies by allowing workers to subscribe to these events. Then the business logic that used to live in the Active Record model after action methods could be moved into bespoke Service classes that the workers could call based on the Event topic.

class BackgroundEventWorker
  def self.route(event)
    ServiceFactory.for(event).call(event)
  end

  class ServiceFactory
    def self.for(event)
      case event[:topic]
      when 'created_user'
        CreatedUserService
      when 'updated_user'
        UpdatedUserService
      else
        ->(event) {}
      end
    end
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment