{"id":227,"date":"2015-02-13T10:32:32","date_gmt":"2015-02-13T10:32:32","guid":{"rendered":"https:\/\/redbooth.com\/engineering\/?p=227"},"modified":"2015-02-13T10:46:38","modified_gmt":"2015-02-13T10:46:38","slug":"using-events-decouple-rails-applications","status":"publish","type":"post","link":"https:\/\/redbooth.com\/engineering\/patterns\/using-events-decouple-rails-applications","title":{"rendered":"Using events to decouple Rails applications"},"content":{"rendered":"<p>During the last years Rails developers have been looking for ways to move from monolithic to component-based applications. One of these is the use of <a href=\"http:\/\/guides.rubyonrails.org\/engines.html\">Rails Engines<\/a>. The basic idea is to move away from the default MVC Rails architecture where &#8220;fat Models&#8221; end up being morbid obese.<\/p>\n<p>If you are interested to know more about Rails Engines I highly recommend you to watch these two talks by Stephan Hagemann at <a href=\"https:\/\/www.youtube.com\/watch?v=-54SDanDC00\">Mountain West RubyConf 2013<\/a> and <a href=\"https:\/\/www.youtube.com\/watch?v=MIhlAiMc7tU\">RailsConf 2014<\/a>.<\/p>\n<p>In a few words we&#8217;re talking about code that doesn&#8217;t pertain to your application core business logic but lives around it. Since we recognize that they&#8217;re not part of the core we can extract them into Rails Engines.<\/p>\n<p>A typical example can be to extract email notifications functionality from the core of the application and move it to an Engine.<\/p>\n<h2>Decoupling engines<\/h2>\n<p>The most exciting thing, of course, is not just moving code around. It allows you to create APIs that developers can rely upon to build functionality. By encapsulating a feature to its own engine we can debug better since we know where all the code related to certain functionality is.<\/p>\n<h2>Using observers<\/h2>\n<p>One way to react to the changes of our models in core is to use good old observers. Before we had `ActiveModel::Observer` for that! And we still have it of course. The only issue now is that our observer class name is something like `EmailNotificator::UserObserver` and Rails cannot do the magic of inferring the Model from the class name. That&#8217;s when the convenient `observe` method comes to help. Look at the <a href=\"https:\/\/github.com\/rails\/rails-observers\/blob\/876c522184a4ed26d564833f496ef1bfa7af654a\/lib\/rails\/observers\/active_model\/observing.rb#L307\">code<\/a> to better understand how it works.<\/p>\n<pre># engines\/email_notificator\/app\/observers\/email_notificator\/user_observer.rb\r\nmodule EmailNotificator\r\n  class UserObserver < ActiveModel::Observer\r\n    observe :user\r\n  end\r\nend\r\n<\/pre>\n<p>In this Observer we're subscribing to core `User` model changes. If we need to observe engine specific Models we can do the following instead:<\/p>\n<pre># engines\/email_notificator\/app\/observers\/email_notificator\/person_observer.rb\r\nmodule EmailNotificator\r\n  class UserObserver < ActiveModel::Observer\r\n    observe 'EmailNotificator::Person'\r\n  end\r\nend\r\n<\/pre>\n<h2>Custom events<\/h2>\n<p>When our engine is waiting for a custom event to happen outside the engine itself, for instance waiting for an external service webhook, we need a way to subscribe to it. We can apply the pub\/sub pattern using <a href=\"http:\/\/apidock.com\/rails\/v4.1.8\/ActiveSupport\/Notifications\">ActiveSupport::Notification<\/a>. The idea is to trigger an `ActiveSupport::Notification` event from the core (or another engine) and then let our engine listen to it:<\/p>\n<p>In the case of webhooks we'll probably have a Controller inside an Engine that manages the incoming webhook. We can trigger the event inside the Controller's action:<\/p>\n<pre># engines\/webhook_manager\/app\/controllers\/webhook_manager\/webhook_controller.rb\r\n\r\n  # ...\r\n\r\n  def create\r\n    # code to store the webhook\r\n\r\n    ActiveSupport::Notifications.instrument('webhook.received', options: { extra: 'information' })\r\n  end\r\n\r\n  # ...\r\n<\/pre>\n<p>Then inside our engine code:<\/p>\n<pre># engines\/email_notificator\/config\/initializers\/email_notificator.rb\r\n\r\nActiveSupport::Notifications.subscribe('webhook.received') do |name, start, finish, id, payload|\r\n  # do some stuff here\r\n\r\n  puts \"A webwook has been received with some more extra #{payload[:options][:extra]}\"\r\nend\r\n<\/pre>\n<p>Now every time a `webhook.received` event is triggered our engine will execute the code in the block.<\/p>\n<h2>Conclusions<\/h2>\n<p>Thinking about components that communicate through events can help during the process of breaking monolithic apps into smaller components. It will make your code cleaner and easier to debug (`git grep` friendly). Give it a try!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>During the last years Rails developers have been looking for ways to move from monolithic to component-based applications. One of these is the use of Rails Engines. The basic idea is to move away from the default MVC Rails architecture where &#8220;fat Models&#8221; end up being morbid obese. If you are interested to know more <a class=\"read-more\" href=\"https:\/\/redbooth.com\/engineering\/patterns\/using-events-decouple-rails-applications\">&hellip;&nbsp;<span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,24,7],"tags":[],"class_list":["post-227","post","type-post","status-publish","format-standard","hentry","category-patterns","category-ruby","category-technical"],"_links":{"self":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts\/227","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/comments?post=227"}],"version-history":[{"count":0,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/posts\/227\/revisions"}],"wp:attachment":[{"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/media?parent=227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/categories?post=227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/redbooth.com\/engineering\/wp-json\/wp\/v2\/tags?post=227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}