Making the Static Dynamic

The right stack for the job

Here at Mapillary we believe in dividing our services into small maintainable parts. We use the right stack at the right place. We force ourselves to write clear API:s between our services, no cheating. Our iPhone app uses the same API as our website. A feature developed in one of our server APIs can instantly be used by both our javascript front-end guy as well as our iPhone and Android developers.

The static problem

Our website http://mapillary.com uses the middleman framework and is hosted on heroku, this prevents us from cheating with the APIs. To communicate with our servers we use angularjs, the whole web page is static which is awesome.

However we just recently bumped into a problem. We want some of our links to be socially shareable. If a user finds a beautiful image in our archives (such as this one http://www.mapillary.com/map/im/pXA7tF-BIYMM2gStoOBMrQ) we want them to be able to share that link with their friends. This requires that we fill in our meta tags on the site accordingly. This is where rack is the best of friends.

Rack

Rack lets you write middlewares. A middleware is a piece of code that has access to everything in the HTML request by the user and the HTML response from the server. This is what we came up with. Add the following to your config.ru file.

    # Datamapper is awesome for accesing your database in ruby
    require 'data_mapper'

    # Create an Image object
    class Image
      include DataMapper::Resource
      property :k, String
      property :title, String
    end

    # Setup Database
    DataMapper.setup(:default, ENV['DATABASE_URL'])

    class DYNAMIC_META
      def initialize(app)
        @app = app
      end

      def call(env)
        status, headers, body = @app.call env

        # Check for request path
        if env['REQUEST_PATH']
          # Match it to our specific path
          match = env['REQUEST_PATH'].match(/^\/map\/im\/([^\/]*)$/)
          if match
            key = match[1]
            # If there is a match lookup up the image in our database
            image = Image.all(k: key).first
            if body
              body.each do |line|
                # Replace static content with dynamic content
                if line =~ /.*twitter:.*/
                  line.gsub!(/<meta content='' name='twitter:image:src'>/, "<meta content='https://example.com/#{key}/image.jpg' name='twitter:image:src'>")
                  line.gsub!(/<meta content='' name='twitter:title'>/, "<meta content='#{image.title}' name='twitter:title'>")
                  body = [line]
                end
              end
            end
          end
        end

        [status, headers, body]
      end
    end

    use DYNAMIC_META

Why is this piece of code so magical. Well its the easiest smallest piece of server side include I can think of. It enables us to use middleman and all of the features we love yet having a tiny part of our website to be dynamic.

Tags for this post:
comments powered by Disqus