Use session variables to optimize your user flow

Sessions provide you a nice little data storage feature where the application does not need to get the information directly from the database. So you do not have to persist data in your database and can easily store info about the user on the fly. This is a nice way to enhance the user experience on your page.

Let's say that you want to show some users a new fancy sign up form and the rest the old form. If you store the version of the sign up form in a session variable, you don't need to persist this info in your database.

Read more »

Our Hiring Process

This is our process to hire new team members at Ombu Labs. It's a process that we have been improving ever since we started our operations. It's very important for us to hire A players.

In this article I will focus on how we evaluate new developers, but parts of the process can be customized for other positions.

Read more »

The Landing Page MVP

There is no good reason why an MVP should take more than one month. If that happens, it means that the scope of the minimum viable product wasn't small enough.

You want to build the smallest feature set in order to start learning from your target market. It doesn't have to be feature complete. It doesn't even have to offer a feature. It doesn't even need to be a web-based MVP.

Read more »

Hunting Down a Slow Rails Request

Recently, we started using Skylight in production for one of our clients' Rails applications, in an attempt to try to improve the performance of some of the more critical API endpoints.

Skylight reports on:

  • Time taken per request
  • Breakdown of time taken per SQL query
  • Object allocations per request

I noticed an unusually large amount of allocated objects for one request:

Skylight report

This request would take anywhere from 400ms to 3000ms to respond, which is WAY too long.

Read more »

10 Steps to Evaluate a Rails Project

It will come a time when you will have to decide whether to maintain a Rails project or not.

If you want to seriously consider it, you should follow these 10 steps:

1. Setup the development environment

Git clone the repository and try to start the server. Is the README clear enough? Can you follow the steps in the file and easily get started?

A lot of projects will have a README that is out of date and/or instructions that don't work right off the bat.

Most of the projects will define guidelines like these:

  • Configure your config/database.yml
  • Configure your .env file
  • Setup the database rake db:create db:migrate db:seed
  • Start the server rails server

The best projects will have a one-liner that will setup the entire environment for you.

Read more »

Set up and run Hubot without using Heroku

Hubot makes it incredibly easy to setup on a Heroku server, by taking advantage of its Procfile support. Simply running git push heroku master deploys the app and starts it.

When it comes to deploying to your own Linux server, given that foreman doesn't really like background processes (see: ddollar/foreman#65), you need to use something like monit, systemd or tmux to better manage your Hubot process.

Read more »

Protect your sensitive data in Git

If you are working with open source or if you are going to open source a repository, you should ensure that none of your sensitive data (API Keys, Credentials, Passwords) can be accessed by anyone.

One thing that a lot of people forget, is that this information stay forever in your repository history, if you do not rewrite the history of your repository.

For instance, what usually happens is that you commit a file with sensitive information. In this Example I added accidentally my ssh-key to the repo:

$ git commit -am 'init git repo'
[master (root-commit) 917a1e1] init git repo
 2 files changed, 52 insertions(+)
 create mode 100644 id_rsa
 create mode 100644 id_rsa.pub

After doing a couple of additions, working and editing, I realise that I should never have commited the ssh-key. *facepalm*

Alright, then I just do a simple git rm --cached id_rsa and everything is back to normal. I also add this file to a .gitignore, so that this cannot happen in the future anymore.

(master) $ git rm --cached id_rsa
rm 'id_rsa'
(master) $ git status
A  .gitignore
D  id_rsa
(master) $ git commit -am 'remove id_rsa'
[master c69deb9] remove id_rsa
 2 files changed, 1 insertion(+), 51 deletions(-)
 create mode 100644 .gitignore
 delete mode 100644 id_rsa

So if we now have a look in our commit list, we can still see our first commit where I added my ssh-key. If I checkout this commit, I still have the contents of my ssh-key available.

(master) $ git log
917a1e1 - init git repo (24 minutes ago) <Sirko Sittig>
(master) $ git checkout 917a1e1
((detached from 917a1e1)) $ cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAoequrqsM42na3OpvBFYOpqvzJumr3/kxJTuluXbPyJzVjMXf
d/uhFUJgSqq4AJGOFLLPpQ+9jwfA+WraIxZ9R7p8LgpNdUwKsmGnUvofeD/9Rs1y
YZO8EAjl1URLJ379nN+L5KKPS/48Q4iGp57iwuGzrXLHccLyW5+Z0iMuHlKBQzPx
...

To ensure that ALL of this data gets properly removed, I need to remove this file from all the commits in the repository with git filter-branch. The command git rm --cached git rm docs is not sufficient in this case.

(master) $ git filter-branch --tree-filter 'rm -f id_rsa' HEAD
Rewrite c69deb9779a30e6335ab1a8ac1a0825cfc9302e4 (6/6)
Ref 'refs/heads/master' was rewritten

So far so good, but what about my other branches that have been created? bash (master) $ git checkout new-feature (new-feature) $ ls drwxrwxr-x 3 sirko sirko 4096 Dec 31 13:20 ./ drwx------ 56 sirko sirko 12288 Dec 31 12:37 ../ drwxrwxr-x 8 sirko sirko 4096 Dec 31 13:20 .git/ -rw-rw-r-- 1 sirko sirko 3243 Dec 31 13:20 id_rsa -rw-r--r-- 1 sirko sirko 748 Dec 31 12:41 id_rsa.pub -rw-rw-r-- 1 sirko sirko 64 Dec 31 13:20 my_document.txt

Apparently git filter-branch is applying this changes only to the current branch, which is actually not what I want. To make this work, it seems that I have to run git filter-branch in every existing branch, which makes it pretty annoying. After reading more in the (git docs)[https://git-scm.com/docs/git-filter-branch], I found that I need to apply the --all option.

(master) $ git filter-branch --tree-filter 'rm -f id_rsa' HEAD --all
Rewrite c69deb9779a30e6335ab1a8ac1a0825cfc9302e4 (7/7)
Ref 'refs/heads/master' was rewritten
WARNING: Ref 'refs/heads/master' is unchanged
Ref 'refs/remotes/origin/master' was rewritten
WARNING: Ref 'refs/remotes/origin/master' is unchanged
Ref 'refs/remotes/origin/new-feature' was rewritten
(master) $ git checkout new-feature
(new-feature) $ ll
total 44
drwxrwxr-x  3 sirko sirko  4096 Dec 31 13:41 ./
drwx------ 57 sirko sirko 12288 Dec 31 13:41 ../
drwxrwxr-x  8 sirko sirko  4096 Dec 31 13:41 .git/
-rw-rw-r--  1 sirko sirko   748 Dec 31 13:41 id_rsa.pub
-rw-rw-r--  1 sirko sirko    64 Dec 31 13:41 my_document.txt

That seems to be exactly what I want and in the end I just need to git push --all --force my changes. After doing this, all collaborators should dump their local versions and clone a fresh version from the origin.

Another alternative to working with git filter-branch is BFG which has some more nifty features.

This tool provides some commands to completely remove big files as well as passwords from your Git history. Sadly I could not get it properly working, big files are still persistent as a git object and passwords can not be deleted because they are protected by 'HEAD'. I could not really find a solution for these problems. Maybe you are more lucky!

The easiest and much simpler solution is to initialize a new git repository, after making sure to have all sensitive information removed. The downside is obviously the loss of the project's Git history.

Read more »

How to report a bug

The simplest way to contribute to an open source project is to file an issue. Here are a few steps for you to file issues that are useful for the project maintainers.

1. Make sure it hasn't been reported yet

A quick Google search should return one or more results about the issue. If it's user error, just change the way you are using the code and move on.

If that doesn't work, find the project (it's probably on Github) and search through open and closed issues. If it's filed and open, try to add more information to make it easier to solve. (Please please please don't just add another +1 to a series of +1s)

If you couldn't find any issues, submit an issue (Beware: some projects will encourage you to post to their mailing list before filing an issue)

2. Submit a useful issue report

Don't just post the title of the error and what you were doing when it happened.

Please be as specific as possible!

Post information about:

  • The environment (a snapshot of Gemfile.lock could help)
  • The error message (a good candidate for the issue's title)
  • The backtrace should always be included in the description
  • If there is some configuration involved, add it to the description

3. Bonus points

  • Try a couple of alternatives and see what results you get. Save all the output, which might be useful for the issue's resolution. I know that most of us try different solutions before filing an issue.

  • If you want to show the maintainer an example of the problem, you could create a sample application that generates the problem, using the same configuration and the same dependencies you have in your application.

  • If you found the problematic line in the library, you could enhance the tests to cover the scenario that you are seeing. The best libraries have near 100% code coverage, so adding another scenario could be easier than you think. You don't need to find the solution, but seeing a failing spec will definitely make it easier to find a solution.

4. Share your monkeypatch

Most of us will monkeypatch our application and move on. This sucks!

You should file the issue, so that other programmers will benefit from your "wasted" effort.

If you monkeypatched it in a horrible way, add it to the issue as well. The project maintainer or other programmers might find that it isn't such a horrible patch after all.

To sum things up

I've explained a couple of ways that you can make a contribution to an open source project. I started with the simpler steps and then I moved on to the more advanced contributions.

Ideally, detailed issue reports will become pull requests in the future. You (or someone else) might send the pull request, but it all begins with a detailed description of the problem you are seeing.

Don't just say "It doesn't work!", don't be that person! Next time file an issue so that we can all benefit from your pain.

Read more »

Adding Docker to a Ruby gem

As a maintainer of a few Ruby gems, I have to decide what is accepted and what gets rejected into the gems. The other day someone submitted a pull request to add a Dockerfile to DatabaseCleaner

I thought it was a good idea, because the current version of DatabaseCleaner requires you to have Postgres, MySQL, Redis, and Mongo up and running before you run rake.

Here are the steps:

  1. Download the Docker Toolbox, a 176+ MB package.

  2. Install the package, which will expand to 400+ MB in your filesystem.

  3. In the terminal: docker-machine start default

  4. Then within your project: docker-compose up (before this I had to run eval "$(docker-machine env default)" because of this issue). Get ready to wait for a few minutes while it sets up your virtual machine.

  5. Finally: docker-compose run --rm gem

Read more »

Adding Csrf-Protection to your Rails-Backbone App

When integrating Backbone.js in your Rails App, you might face the problem of the inability to verify the CSRF-Token.

The CSRF Protection secures your app with a token. Rails makes sure that the person who is interacting with your app is someone who started a session in your site, not some random attacker from another site. So you should not turn it off, unless you know what you are doing.

For more information on this Topic, check out the Rails Security Guide.

This problem occurs as soon as you are trying to send form data, without the CSRF-Token provided by Rails.

Started POST "/products" for 127.0.0.1 at 2015-12-16 10:06:05 -0300
Processing by ProductsController#create as JSON
  Parameters: {"product"=>{"name"=>"foo"}}
WARNING: Can't verify CSRF token authenticity
...
Completed 302 Found in 7.6ms (ActiveRecord: 0.8ms)

After this request, Rails will terminate your session and you will have to login again.

This problem is caused by your Backbone.js application, which is sending the data directly to the backend without providing the CSRF-Token.

To solve this problem you need to add the token to your Backbone request. One of the simplest solutions I came across is the following by Anton Shuvalov.

// https://github.com/shuvalov-anton/backbone-rails-sync
Backbone._sync = Backbone.sync;
Backbone.sync = function(method, model, options) {
  if (!options.noCSRF) {
    var beforeSend = options.beforeSend;

    // Set X-CSRF-Token HTTP header
    options.beforeSend = function(xhr) {
      var token = $('meta[name="csrf-token"]').attr('content');
      if (token) { xhr.setRequestHeader('X-CSRF-Token', token); }
      if (beforeSend) { return beforeSend.apply(this, arguments); }
    };
  }
  return Backbone._sync(method, model, options);
};

It grabs the CSRF-Token provided in the meta tags of your Rails application and sets it for the request header field X-CSRF-Token.

After adding this to the Backbone code, it works as expected.

Started POST "/products" for 127.0.0.1 at 2015-12-16 10:08:29 -0300
Processing by ProductsController#create as JSON
  Parameters: {"product"=>{"name"=>"foo"}}
...
Completed 200 OK in 40.6ms (Views: 0.6ms | ActiveRecord: 10.3ms)
Read more »

How to interact with hidden elements with Protractor

The other day I was trying to interact with a hidden file input field:

<div class="col-sm-3">
  <input class="btn btn-default" class="hidden" accept=".csv"  id="geofence_file_input">
  <a class="btn btn-default" id="textbox-for-geofencefile">Select File</a>
  <span ng-if="LineItemForm.augmentations.geofence.file"></span>
</div>

And the CSS:

.hidden {
  display: none;
}

Which caused this problem:

Failed: Wait timed out after 100015ms

Workarounds include displaying it, interacting with it, hiding it again, which I didn't like.

Read more »

Time and Material

As of 2016, we will no longer work with clients on fixed bid projects. They are not a good fit for us and we are not a good fit for them.

All of our clients are startups. Fixed bids are counterproductive for startups. They give the client a false sense of security and they punish changing requirements.

Fixed bids make clients think that their project will be finished in a fixed period of time if their requirements don't change while developing the project. That is a big if!

Read more »