Michael de Silva's Blog

Software Engineer. Rubyist and Roboticist.

Michael de Silva's Blog

Software Engineer. Rubyist and Roboticist.

Got an app in mind?

Since 2010, I have crafted apps for mobile and web for clients around the world via my consultancy — Inertialbox. My specialities include Rails, client-side Javascript frameworks such as Backbone & Ember.js, TDD/BDD, and DevOps — just to name a few.

We should talk.

Dissecting The Latest Spree and Solidus API Security Vulnerability

Screen shot 2015 07 24 at 23.38.42

Even though this vulnerability was announced on July 17th, I just happened to stumble on a tweet about it.

The important bit to look at in the source is this

diff --git a/api/lib/spree/api/responders/rabl_template.rb b/api/lib/spree/api/responders/rabl_template.rb
index 4a061f4..0b0d31c 100644
--- a/api/lib/spree/api/responders/rabl_template.rb
+++ b/api/lib/spree/api/responders/rabl_template.rb
@@ -14,7 +14,7 @@ module Spree

         def template
-          request.headers['X-Spree-Template'] || controller.params[:template] || options[:default_template]
+          options[:default_template]

So, it makes sense that any template can be asked for either via the X-Spree-Template header or template param.

I wanted to verify this, and spun up a copy of Spree I had on my disk, and toyed a bit with a spec, asking for the README.md file in the Spree app rep ...(continued)

Autoglym Product Reviews, Now Get Replies

Screen shot 2015 07 24 at 19.44.26

I wanted to feature some work that I did on the Autoglym app today, specifically adding some minor functionality within Spree. Having spent about 7-months rebuilding a Rails 2.x eCommerce site in Rails 4 means this was a nice change of pace.

The Autoglym app already associates user reviews with products, and today I simply associated those reviews with a reply, so that AG staff can reply to reviews (especially negative feedback?). Part of the scoped work called for Markdown support, which I baked in quite quickly thanks to the excellent Redcarpet gem.

On the frontend, it's some simple SASS styling and visibility logic baked into the view partial. Rather pleased that I was able to turn this around a bit quicker than originally estimated in the 'sprint' scope as well.

Freelance 101: Early Warning Signs of a Troublesome Client

29821232 bad news depressed mature man in shirt and tie talking on the mobile phone and touching face with ha stock photo

Working freelance is never easy, one needs to exercise a bullshit meter at all times, and today mine went off big time.

Having posted my available for work during US hours, I picked up a lead on Twitter. Single dev based in Tokyo, looking for a full-time Ruby dev to offload work to.

Initial emails seemed promising, even though I explained that I couldn't do full-time, but I could do 25 hrs/week. I always make it a priority to work with clients, and this is the first time a client wasn't willing to work with me. More on that shortly!

As far as I'm concerned, a lead (and deal) is never done, until the contract is inked and my advance hits my account. This is quite simply, your very first bullshit test, and an important one to safeguard not only yourself but your time as well. I always ask for an advance as a 'smoke test' to check if the potential client is someone who's serious about the work, or someone looking to simply take advantage of another developer. ...(continued)

Reaching Half a Million Views on YouTube

Screen shot 2015 07 11 at 19.43.06

It has been 9 years since I started actively pursuing my interest in watches. During this time, I have dedicated photographs to watches that were once part of the collection, and later parted with — as well as pieces currently in my small stable.

My first attempt at a watch review was when I got my third Rolex, a two-tone yellow gold and steel GMT-II with Ceramic bezel. At the time, it really was quite special, considering that it had the newer CNC'd bracelet where all the links, steel & gold (18k), were solid instead of hollow like the older stamped bracelet, movement improvements, and much more. These 'improvements' continue in current production Rolexes, and some of these are impervious to the untrained eye or non-WIS (Watch Idiot Savant).

I reca ...(continued)

Stripping sensitive details copied from terminal STDOUT by piping via sed in Mac OS X

Having run into an issue today, I wanted to contribute some error details to an issue on Github, and wanted to strip out details from the output that I'd copied in iTerm.

I was able to pipe the contents of my paste buffer (clipboard) through sed to perform a regexp based search & replace, and pipe the cleaned output into TextMate.

$ pbpaste | sed "s/inertialbox/foo/g" | mate

Here's the output!

ERROR in ./~/css-loader!./~/sass-loader?outputStyle=expanded!./src/styles/Imagebox.sass
Module build failed:
      Invalid top-level expression
      in /Volumes/foo/hack/node/react-webpack-example/src/styles/Imagebox.sass (line 1, column 1)
 @ ./src/styles/Imagebox.sass 4:14-298
INFO [karma]: Karma v0.12.37 server started at http://localhost:8080/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Mac OS X 0.0.0)]: Connected on socket VvzYKnxwnjInFmolV93m with id 20249201
PhantomJS 1.9.8 (Mac OS X 0.0.0) ERROR

Faking APIs in Development and Staging

Riddle sinatra lg

Having used Webmock and VCR in past projects, there have been times when I'd spawn an instance of Sinatra, just to hit an API end-point, but this is certainly a better way to go about it.

module FakeMovieFacts
  class Application < Sinatra::Base
    get "/movies/:movie_name/actors" do
        actors: [
            name: "Actor 1",
            character_played: "Character 1"
            name: "Actor 2",
            character_played: "Character 2"

Initialize this as a new gem with bundle gem fake_movie_facts and extract FakeMovieFacts::Application (above) into fake_movie_facts/lib/fake_movie_facts/application.rb and add a config.ru file to the root of the repo

# config.ru

$LOAD_PATH << File.expand_path("../lib", __FILE)
require "fake_movie_facts/application"

run FakeMovieFacts::Application

You can either run th ...(continued)

When that Startup Interviewer cares more about where you're from

For the past couple years, I've been primarily working for a client based in the UK. I'm lucky to work with a fantastic team and I have no complaints there. The only downside, is the sort of work that comes through the doors, although I'm of course grateful that we have work!

The thing is, the client in question is a design firm, and this kind of work is all about work that has been scoped on a project-basis. You basically get an X-number of hours to get the project done and dusted; fall shy of that estimate and things start to get hot under the collar!

While this may not be apparent, there's a different approach to life as a programmer, and that's the startup scene. Rather than hopping around multiple client-projects, hell bent on profit vs. quality, at startups there's typically a single product. Remember 37 Signals, had Highrise, Campfire... and they renamed themselves Basecamp — it's actually one of the best things they did since sharing Rails with ...(continued)

Suits is back, with Season 5 and Under the Dome

Wallpaper suits 34619277 1920 1080

It's great news, Suits is back as Season 5. Can't wait to catch the premier.

Also, Under the Dome Season 3's just started with what looks like an hour long premier.

Improving my Dockerised App stack

Here's a quick update on my app stack — which is saving me a further $20/mo. A previous iteration of this stack, before it was Dockerised, has now been scrubbed off the Digital Ocean servers, and that app — inertialbox.com — is now running on the same 1 GB ten-dollar droplet.

There's ~300MB of RAM free which hasn't affected orchestration via Ansible. The nginx reverse-proxy is also now in place, and it's being treated as an 'app' as well. Since it's running in a container, it's just another service and therfore is fair to consider it in the same vein.

All the following containers are managed by systemd, and I'm quite frankly loving it along with the journald.

CONTAINER ID        IMAGE                                 COMMAND                CREATED             STATUS              PORTS                    NAMES
4f1ba395455e        ...(continued)

Jack Dorsey is CEO at Twitter, so here's a TODO list

I was watching the Bloomberg clip on Verge and the main topic of discussions was why Twitter is stuck at 300M users, and how come they've had a Billion signup & never come back (bounce-adoption rate?).

Here's my TODO list for Jack Dorsey

Simple Signup

Think 'KISS', or better known as 'Keep It Simple Stupid'. It's not rocket science. Signing up right now is far too long-winded, and rather than having users pick those to follow at signup, give them an auto-populated list from the 'verified' accounts list.

Show new users the value of Twitter

Lot of non-techies have no clue what twitter is, or its value. I personally use it as a news-source, and many do. Perhaps give new users an insight into this upon sign up.

Twitter needs Chirps - long tweets.

That 140-char limit will hurt your user base. Something to che ...(continued)

Replace a MySQL table in Production via a Rails 4 Migration

In a recent client project, I've been re-building a Rails 2.x eCommerce site in Rails 4.2, and when this is launched on production, I wanted to be able to drop tarballs of various tables straight into the git repo and have a migration unpack those tarballs and import them into the DB; the drop-table clauses in the SQL will ensure existing tables will be selectively replaced upon import.

The entire unpacking of the compressed tarball is done in memory, and the script looks for the file in the bootstrap folder in the app root. The database.yml file is used to fetch login credentials, and that's how the extracted SQL file is imported into MySQL.

require 'rubygems'
require 'rubygems/package'
require 'zlib'
require 'fileutils'

module Util
  module Tar
    # Creates a tar file in memory recursively
    # from the given path.
    # Returns a StringIO whose underlying String
    # is the contents of the tar file.
    def tar(path)
      ta ...(continued)

Post Archive