Rails: Rest API post-mortem analysis

This is a personal post-mortem analysis of a project that was mainly build to provide a REST API to mobile clients.

For the API backend we used the following components:

  • Active Model Serializer (AMS) to serializer our Active Record models to JSON.
  • JSON Schema to test the responses of our server.
  • SwaggerUI to document the API.

It worked

The concept worked really good. Here are two points that were extraordinary compared to normal Rails project with many UI components:

  • Having a Rails application, that has no UI components (only...

Geordi 2.7.0 released

  • Fixed #68: The "cucumber" command now fails early when @solo features fail.
  • Added: The "setup" command now prints the db adapter when prompting db credentials.
  • Fixed #71: When used without staged changes, the "commit" command will print a warning and create an empty commit. Any arguments to the command are forwarded to Git.
  • Fixed: The "commit" command will not print the extra message any more.
  • Added: The "commit" command prints a (progre...

Bookmarklet to generate a Pivotal Tracker story from Zammad Ticket

This is a bookmarklet you can add to Chrome or Firefox which will allow you to create a story in Pivotal Tracker from a Zammad ticket. This might come in handy when creating stories for SWAT Teams.

But first you will have to set two variables in the script below:

  • pt_project_id: the ID of the Pivotal Tracker Project you want to add stories to. This can be found as part of the URL of the project (https://www.pivotaltracker.com/n/projects/<pt_project_id>)
  • pt_token: the Pivotal Tracker token used for authentication. Can be found in y...

Guidelines for Pull Requests and Code Reviews

Projects with more than one developer should always consider to enforce code review even for small changes to improves the overall code health of the system. Here are some guidelines that can help you to accomplish this task.

Github

How to write the perfect pull request

Google

Google's Engineering Practices documentation
Modern Code Review: A Case Study at Google

Though...

A collection of useful design resources for developers

This collection contains some useful design resources for developers. Many of them were mentioned in the Refactoring UI tutorials.

Tutorials

Integrating or upgrading makandra-rubocop

Introduction

Most of the time it is a tedious task to apply a code style guide to an existing code base as there are likely to be a lot of conflicts. At makandra we are using makandra-rubocop to have code style checks. Here is some advice on how to add makandra-rubocop efficiently.

Note

RubyMine by default has a Rubocop inspection with rules that we don't always agree with. We recommend replacing this with makandra-rubocop or disabling the inspection.
...

Bash script to list commits by Pivotal Tracker ID

The main benefit of our convention to prefix commits by their corresponding Pivotal Tracker ID is that we can easily detect commits that belong to the same story. You can either do that manually or use the bash script below by copying it somewhere to your .bashrc.

# Usage: ptcommits 123456
function ptcommits {
  if test "$1"
  then
    local PTID=$(echo "$1" | grep "[0-9]*" -o) # Allow URLs
    git log --onel...

Capistrano: Finding out who deployed which revision of your application and when

Capistrano automatically logs each (successful) deployment into a file on your application servers.

It is located at the root of your server's project folder, i.e. the parent of releases and current, like so:

/var/www/your-project$ ls
current
log
releases
repo
revisions.log  <---  here
shared

Each line in that file contains the deployed branch, commit, release ID, and username (was read from the deploying user's machine):

$ tail -n3 revisions.log 
Branch master (at da45511bea63002ac2ff002d1692e09d0dd7cb88) deployed as rel...

Restore changes, even from deleted files, with RubyMines "Local History"-Feature

Sometimes, due to git or other "accidents", important files get deleted or overwritten.

At a state when even Ctrl+Z doesn't work anymore, you maybe can rescue your files with RubyMines "Local History"-Feature!

To do this try the following:

  • If the file got deleted, recreate a new empty file with the same name on the exact same place
  • Open that file in the editor
  • Go to RubyMine and click on VCS -> Local History -> Show History
  • In the now open window, you should see all greater changes made to the File, even before it got deleted/temp...

Webpack(er): A primer

webpack is a very powerful asset bundler written in node.js to bundle (ES6) JavaScript modules, stylesheets, images, and other assets for consumption in browsers.

Webpacker is a wrapper around webpack that handles integration with Rails.

This is a short introduction.

Installation

If you haven't already, you need to install node.js and Yarn.

Then, put

gem 'webpacker', '~> 4.x' # check if 4.x is still cu...

Git: Apply a diff

git apply allows you to apply a diff onto your HEAD. Most often you can achieve the same result with a rebase & merge.

Example:

master                commit1 - commit3
feature-branch                \ commit2 - commit4
git checkout feature-branch
git reset --hard commit3
git diff ..commit4 | git apply
master                commit1 - commit3
feature-branch                          \ Unstaged commit 2 & 4

You can also [create a patch and apply it afterwards](https://makandracards.com/makandra/2521-git-how-to...

How to get a backtrace if rspec (or any other ruby process) hangs with no output

If rspec hangs with no output and you dont get a backtrace neither with --backtrace nor by just killing it with crtl-c,
you can put the following in your spec/spec_helper.rb:

puts "rspec pid: #{Process.pid}"

trap 'USR1' do
  threads = Thread.list

  puts
  puts "=" * 80
  puts "Received USR1 signal; printing all #{threads.count} thread backtraces."

  threads.each do |thr|
    description = thr == Thread.main ? "Main thread" : thr.inspect
    puts
    puts "#{description} backtrace: "
    puts thr.backtrace.join("\n")
  end

...

Yarn: How to recognize that you are using a different node version than your colleagues

The issue in this card can occur if the node_modules directory is checked into your Git repository. We usually recommend to exclude node_modules from version control.

In any case you should document which version of node to use in your project in a .nvmrc file.


I saw a strange behaviour after we introduced webpack in one of our projects and finally found out the reason: The person who committed the files used a node version that is older than mine.

Every time I wanted to run my rai...

Webpack: Automatically generating an icon font from .svg files

Over the years we have tried several solution to have vector icons in our applications. There are many ways to achieve this, from SVGs inlined into the HTML, SVGs inlined in CSS, JavaScript-based solutions, to icon fonts.

Out of all these options, the tried and true icon font seems to have the most advantages, since

  • icon fonts are supported everywhere
  • they perform well and require no JavaScript at all
  • their icons align nicely with text
  • their icons automatically inherit color and size of the surrounding text

The big issue used to b...

Migration from the Asset Pipeline to Webpacker

This is a short overview of things that are required to upgrade a project from the Asset Pipeline to Webpacker. Expect this upgrade to take a few days even the diff is quite small afterwards.

Preparations

1. Find all libraries that are bundled with the asset pipeline. You can check the application.js and the application.css for require and import statements. The source of a library is most often a gem or a vendor directory.
2. Find an working example for each library in the application and write it down.
3. Find out the ver...

JavaScript without jQuery (presentation from 2019-01-21)

Summary

  • We want to move away from jQuery in future projects
  • Motivations are performance, bundle size and general trends for the web platform.
  • The native DOM API is much nicer than it used to be, and we can polyfill the missing pieces
  • Unpoly 0.60.0 works with or without jQuery

Is jQuery slow?

From: Sven
To: unpoly@googlegroups.com
Subject: performance on smartphones and tablets

Hello

I just used your framework in one project and must say,
I am really pleased with it -- but only on a desktop computer.

Have you benchm...

How to upgrade Rails: Workflow advice

When upgrading Rails versions -- especially major versions -- you will run into a lot of unique issues, depending on the exact version, and depending on your app.

However, it is still possible to give some generic advice on how you want to tackle the update in principle.

If you are not really confident about upgrading Rails, have a look at Rails LTS.

How many update steps?

Besides the Rails upgrade itself, you might also want to upgrade your other gems and upgrade your Ruby version.
First decide in how many st...

How to: Use different configurations for S3cmd

S3cmd is a free command line tool and client for uploading, retrieving and managing data in Amazon S3. S3cmd reads its configuration by default from ~/.s3cfg, which is created once you run s3cmd --configure.

If you have many configurations, we recommend to always specify the configuration you want to use. This prevents applying actions to the wrong bucket.

Examples:

s3cmd -c ~/.s3cfg-github-staging ls
s3cmd -c ~/.s3cfg-github-development ...

Rbenv: How to remove a gem installed from a Github source

Normally you can list all gems of the current ruby version with gem list, which also includes the gems of you Gemfile. These can be uninstalled with gem uninstall gemname.

List and uninstall a gem installed via Bundler from Github

This does not work for gems installed directly from Github. They do not appear in gem list.

Show all gems installed via Github by bundler:

ls ~/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/bundler/

Remove a gem installed via Github by Bundler:

rm -rf ~/.rbenv/versions/2.4.1/lib/ruby/gems/2....

An incomplete guide to migrate a Rails application from paperclip to carrierwave

In this example we assume that not only the storage gem changes but also the file structure on disc.

A general approach

Part A: Create a commit which includes a script that allows you to copy the existing file to the new file structure.

Part B: Create a commit which removes all paperclip logic and replace it with the same code you used in the first commit

Part A

Here are some implementation details you might want to reuse:

  • Use the existing models to read the files from
  • Use your own carrierwave models to write t...