Stac Blog

November 25th, 2014 by Josh

Log tagging in Rails

Sometimes when debugging issues in a live application, it can be hard to pair up log entries with application requests. The water can become even murkier when you've got many application processes accepting requests from multiple entry points (such as a load balancer).

One way of dealing with this is to tag each request with a unique ID, and use that ID to trace the request throughout its lifespan. Heroku has a great article on HTTP request IDs over here.

We needed to do this recently whilst deploying a large application to the Heroku platform, so we decided to look into log tags within Rails.

It's quite simple to get tags showing up in your Rails logs. Say we want to show the current request ID against each log entry, all we need to do is configure the log_tags setting in an initializer:

# config/initializers/log_tags.rb

My::Application.config.log_tags = [ :uuid ]

Now you can filter the log content by a particular request ID to see all output related to a single request (including any requests to assets if you are using Rails to serve static assets). Some services let you search for keywords in logs (such as PaperTrail) which can make this process easier.

For example, a controller request before tagging might look like this:

Started GET "/dashboard" for 127.0.0.1 at 2014-11-24 15:48:30 +0000

And after:

[a00c54e0-874f-4358-a7b9-accef0c407c6] Started GET "/dashboard" for 127.0.0.1 at 2014-11-24 15:48:30 +0000

This is particularly useful on Heroku, as they set X-Request-ID at the routing layer, meaning we can trace the request from the very start when the request gets accepted by the router (before it hits any of your application dynos).

It's worth noting that if X-Request-ID is not set, Rails will generate a unique ID for the request itself, meaning you can still use this feature.

As well as :uuid there are many other symbols you can use to provide more useful tags in your logs such as :host and :remote_ip. You can also provide a lambda/proc as an item in the settings array should you need to define more custom behaviour.

July 25th, 2014 by Josh

Hey!Stac Relaunched

Hey!Stac

Since we launched Hey!Stac a year ago, we've put on 12 events, had 35 talks and scoffed 704 brownies. Following a successful year we wanted to take stock of what the brand had become and where we wanted to take it in the future.

The end result was a new brand and site which presents the content in a way which allows it to be explored, and a new event format which we're launching in August.

You can read more about our plans for the future over here.

July 11th, 2014 by Josh

Case Study: NHSx

It's not often that you get a call from the NHS asking you to build a learning platform from scratch, using the latest technologies and delivered using agile management practices, but one February morning we were faced with exactly that.

Alongside good friend Harry Roberts (who's also done a nice write up of the project here) we met Jason, the NHS Leadership Academy’s Programme Lead, and after a short discussion we agreed this was definitely a project we'd like to be involved in.

NHSx

Overview

The aim of the project was to build a learning platform that could be used to distribute educational content to anyone, at any level within the NHS. Whether they're a nurse or an executive, the platform needed to provide a place for them to take part in online programmes and report their progress back to coaches and programme leads.

On top of this, we also needed to make sure that the content packages were easy to author and manipulate. The platform needed to satisfy the users who administered the programme content just as much as the participants, as the quality of the content was just as important. There were already systems out there that supported a variant of what we needed, but they didn't fit the delivery model we had in mind, so we worked with the authors to build something more suitable for the platform. This resulted in a custom package format that meant authors could create learning content, add resources such as videos and images, and bundle it all up into a single upload to publish on the platform.

Process

One of the most refreshing aspects to this project was how it was run and delivered. IT projects in the public sector are mostly publicised for being monolithic beasts resulting in bloated software and off-the-mark deliverables, but I'm glad to say that this project couldn't have been more different. It's a huge credit to Jason and his team that the project was delivered on time and to the specification.

On top of that, it was all done in an agile manner. We used tools like Trello and Slack to keep communication tight, and GitHub to keep conversations around code focused and relevant. During a series of 14 sprints we took the project from MVP to final deliverable. We used a staging server to preview code before production releases to ensure internally we were happy with how things worked, and we used automated deployment processes to push code live.

It was made even more enjoyable by Jason allowing the development team to just "get things done" without too much bike-shedding about how we were doing things, with the knowledge that we had the experience to deliver what was asked of us.

Detail

The main platform project was build in Rails 4, using a small handful of gems to speed up development of some common features. Alongside this, Harry worked on a UI Toolkit written in Sass. We worked on the functional and presentational sides of the application in separate branches (using Git), until we were ready to pair the work up.

A bit more detail about the technology used on this project:

  • To run the app itself we used Foreman and Unicorn. Using Unicorn allowed us to deploy the app with zero downtime using rolling restarts
  • Dragonfly was used a lot, not only for image uploads, but storing assets and content packages, and post-processing assets into cloud storage
  • App Signal meant we were notified of any production errors or performance regressions
  • Rack Cache helped us tune some heavy page requests and dragonfly downloads
  • Ember.js allowed us to create mini applications that we could embed into certain parts of the site which required richer features (such as private user portfolios)
  • jBuilder helped us build a more consistent API for the JavaScript applications by treating our JSON views just like any other Rails view
  • Capybara and Site Prism allowed us to thoroughly test the entire stack, along with the usual unit and controller specs

Alongside the technologies listed above we also created some private gems to support some more bespoke features of the platform such as content delivery (which used our custom package format), application permissions, and feature flags so we could easily enable features for certain participants.

Summary

It was a pleasure to be a part of such an agile team, especially on a project with such a large impact on its user base. We can't wait to see how the project evolves and matures as more learning content gets added, and we look forward to seeing the Leadership Academy continue to improve the jobs and lives of people who have used the platform, delivered by a small team in just a few months.

April 15th, 2014 by Josh

Action Mailer Interceptors

There's a little known feature in ActionMailer called Interceptors. If you've ever wanted to conditionally alter an outgoing email within a Rails application, Interceptors are what you're looking for.

Interceptors allow you to do exactly that, intercept an outgoing email. It's at this point you can choose to alter the to address, add a BCC address, or stop the mail from sending altogether.

Example

Let's look at how Interceptors work. Firstly, define a class which responds to the .delivering_email class method. This will accept a single argument, the mail object:

class RedirectOutgoingMails
  class << self

    def delivering_email(mail)
      mail.to = 'test@example.com'
    end

  end
end

In the above Interceptor, we're overriding the to address to only send to test@example.com regardless of who the mail was meant to go to.

Now the Interceptor needs registering with ActionMailer:

ActionMailer::Base.register_interceptor(RedirectOutgoingMails)

Once registered, this will intercept all mails. This might not be what you want, so let's look at adding it only for certain environments:

if %w( development staging ).include?(Rails.env)
  ActionMailer::Base.register_interceptor(RedirectOutgoingMails)
end

Now we'll only have the mails intercepted in our development or staging environments. This can be particularly useful if you use sample data from production on staging, and don't want to accidentally email real users (although we wouldn't recommend directly using live data on staging).

Other Uses

As we have access to the entire mail object, we can do more than just alter the to address. We can, for example, stop delivery of the mail altogether:

class HaltMailDelivery
  class << self

    def delivering_email(mail)
      mail.perform_deliveries = false
    end

  end
end

Or we could BCC in all admin users to all emails:

class BccAdminsToAllMails
  class << self

    def delivering_email(mail)
      mail.bcc = User.where('admin = ?', true).pluck(:email)
    end

  end
end

Refactoring

One slight improvement we could make to the original example is to source the override email addresses from the ENV constant, so we don't need to make code changes when we want to change the to addresses:

class RedirectOutgoingMails
  class << self

    def delivering_email(mail)
      mail.to = to_addresses
    end

    def to_addresses
      raw = ENV['MAIL_INTERCEPT_ADDRESSES'] || ''
      raw.split(',').map(&:strip)
    end

  end
end

Now all we need to do is change the config value in MAIL_INTERCEPT_ADDRESSES and restart our application and the changes will take effect.

January 27th, 2014 by Josh

2013 Recap & Latest News

Better late than never, we wanted to take a moment to recap last year and provide a brief update of plans moving forward. 2013 was a great year for Stac, and we're incredibly excited about what we've got lined up for this year.

Hey!Stac

June saw the first Hey!Stac event take place just below Stac HQ in The Faversham. Since then, we've seen a great community grow with many loyal, familiar faces.

With 17 talks so far, focusing on a wide range of topics from development to mental health, we're really interested to see where we can take the event over the next year.

Hey!Stac's aim has always been to build and support a community of skilled and passionate people, whether they're developers, designers, writers, project managers or business owners.

This year we're focusing on putting more effort into planning the events and supporting speakers to ensure we can keep things flowing. In light of this, we're happy to announce the next three events will be on the 28th January, 25th February and the 25th March.

We're also looking for formal sponsorships to ensure that we can put on the best events possible; if you're a company looking to get involved, please get in touch.

Client Success

New Year's Eve saw the conclusion of a year long project to launch the next iteration of our Manchester client Fatsoma's ticket sales platform. It was great to see them top a new record in sales over the Christmas period, and we're sure that the success of the platform and the business itself will continue to grow as they expand their team. It's been a pleasure working with a company with such a clear vision on how the future of ticketing should be, and we're proud to have played a part in that.

Leeds, Manchester and London

Alongside Leeds and Manchester we're excited to add London as a third location for Stac. With a thriving startup culture and many interesting technical problems to solve we're really keen to meet businesses who we can support and grow with. Although we're taking our offering down to the capital, we're not abandoning our northern roots, and Leeds will remain firmly planted as our base.

Blog Content

We're also looking forward to putting more effort into publishing content surrounding Rails and Ember.js, as well as other non-technical posts. Keep an eye out for more posts coming soon.

Thanks to all our clients and the community that's supported us through 2013, we hope to see many new faces at our upcoming events, and here's to 2014!

October 31st, 2013 by Josh

Creating A Rails-Style Flash Object With Ember.js

If you've used Rails for a while you'll be familiar with flash messages. Flash objects provide a way to temporarily store information to recall later (usually on the next page render). This can be really useful for performing an action in a controller and then setting a feedback message to show the user during the next action.

We've done a lot of work with Ember.js lately, and we needed this functionality to feedback model saves to the user. There are already a wide variety of solutions out there, including the awesome Growl-esque notifications by Aaron Haurwitz, but for one of our smaller projects we wanted something simpler.

We're already using Foundation for it's excellent grid system, so we wanted to re-purpose the alert component into Ember.js flash object.

You can view the complete demo here, what follows is a break down of each concern. Please note that this demo assumes you have the Foundation CSS and Ember.js loaded on the page.

Model

Firstly, we'll create the flash model, responsible for storing information such as the type of message (alert and success) and the message content itself.

App.FlashModel = Ember.Object.extend({

  type : null,

  message : null,

  isAlert : Ember.computed.equal('type', 'alert'),

  isSuccess : Ember.computed.equal('type', 'success'),

  clear : function(){
    this.update(null, null);
  },

  update : function(type, message){
    this.set('type', type);
    this.set('message', message);
  },

  success : function(message){
    this.update('success', message);
  },

  alert : function(message){
    this.update('alert', message);
  }

});

View

Then we'll create a view, which will be backed by the flash model. This is responsible for binding to model properties and ensuring the view reflects the current model state. It also handles hiding the modal by clearing the flash data from the model on a click event.

App.FlashView = Ember.View.extend({

  templateName : 'flash',

  classNames : [ 'alert-box' ],

  classNameBindings : [ 'success', 'alert' ],

  messageBinding : 'model.message',

  alertBinding : 'model.isAlert',

  successBinding : 'model.isSuccess',

  isEmpty : Ember.computed.empty('message'),

  didInsertElement : function(){
    if(this.get('isEmpty'))
      this.hide();
  },

  onMessageChange : function(){
    this.get('isEmpty') ? this.hide() : this.show();
  }.observes('message'),

  hide : function(){
    this.$().hide();
  },

  show : function(){
    this.$().show();
  },

  click : function(e){
    e.preventDefault();
    this.get('model').clear();
  }

});

Template

As well as the view object itself, we'll create the template, which simply renders the flash message. All foundation classes are taken care of by the view object.


Application

Now we'll write the glue code which uses the flash object (for the purposes of this demo only). We'll create an Ember application object, which acts as the namespace for everything app related. All views and models will be stored on this object.

App = Ember.Application.create();

Alongside the application object, we'll want to add a template, which renders the current route via the outlet and the flash view as part of the main app layout. The flash view binds the model to the global App.flash object (which we'll set later on).


Then we'll define an index view and route. The view defines action triggers which call actions within the route that change the state of the flash object.


App.IndexRoute = Ember.Route.extend({

  actions : {

    setSuccess : function(){
      App.get('flash').success('This is a success message.');
    },

    setAlert : function(){
      App.get('flash').alert('This is an alert message!');
    },

    setCleared : function(){
      App.get('flash').clear();
    }

  }

});

Finally, we'll create an instance of the flash on the application (which is used in the application layout).

App.set('flash', App.FlashModel.create());

Summary

This demo reveals some of the power behind Ember.js. Computed properties and bound objects are concepts that really help keep your code concise and tidy. After using Ember for only 6 months, we can't imagine how we made large JavaScript apps without it.

Hat tip to Luqman Amjad for working with me on the initial component.