Install PostGIS for pgvm

Say you're using pgvm to manage several versions of Postgres and you need to install the PostGIS extension.

Prerequisites:

  • If you have installed PostGIS via brew before, uninstall it:
$ brew uninstall postgis
  • Install your favorite Postgres version via pgvm:
$ pgvm install 9.3.12
  • Use the Postgres version you want to install PostGIS to:
$ pgvm use 9.3.12
  • Create and start a pgvm cluster:
$ pgvm cluster create my_cluster
$ pgvm cluster start my_cluster
  • Set the environment variable PGPORT ...

group_by with ActiveModel::Serializers

When using group_by in a controller that serializes the grouped collection to JSON you will notice that your serializers created with the active_model_serializer will not be used and all attributes in your model are just converted to JSON. For example:

class SomeModel 
  #attributes: :name, :body, :some_group_key
end

class SomeModelSerializer 
  attributes :name
end

# in controller
def index
  @some_models = SomeModel.all.group_by(&:some_group_key)
  render json: @some_models, each_serializer: SomeModelSerializer
end

So this w...

.first and .last on models using uuid

Normally, your rails model is backed by an Integer as ID. So User.first leads to:

SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1

That does not work with UUIDs (e.g. "028edf8c-c61c-40bc-a11c-27e90a7f373c").

Solution: Define custom methods on the class:

# replacement for .first/.last because we use uuids
def self.first
  order("users.created_at").first
end
  
def self.last
  order("users.created_at DESC").first
end

Show the routing table on MacOS

When things get weird with your internet connection and you can't even ping the router's IP, you should have a look at the routing table:

  $ netstat -nr

It gives you:

netstat -nr
Routing tables

Internet:
Destination        Gateway            Flags        Refs      Use   Netif Expire
default            192.168.1.3        UGSc          131        0     en6
127                127.0.0.1          UCS             0        0     lo0
127.0.0.1          127.0.0.1          UH              9      448     lo0
127.94.0.1         127.94.0...

'PG::GroupingError: ERROR: column must appear in the GROUP BY clause or be used in an aggregate function' in rails while trying ".group"

TL;DR:

If you have an ordering scope on a column of your ActiveRecord model, that must appear in the result set of the group clause. You need to get rid of the scope with ActiveRecord::Base.unscoped to get SomeArModel.group(:some_column).count(:id_column) working.

Example

If you try to do the following:

 Article.group(:visible_to_readers).count(:id)

And you have a default scope on your model:

class Article < ActiveRecord::Base
  default_scope -> { order(published_at: :desc) }
end

Then you will get the f...

a bookmarklet to generate the commit message from an open jira story

javascript: (function ($) {
  var branchName = "nothing found" ;
  var story = jQuery(".ghx-fieldname-issuekey a");
  if(story){
    var title = $("[data-field-id='summary']").text();
    var id = story.text();
    
    var translate = {
      "ä": "ae", "ö": "oe", "ü": "ue", "ß": "ss"
    };
    
    var storyType = "feature";

    var commitMessage = "[" +  id + "] " + title;

    prompt('Your commit message:', commitMessage);
  } else {
    alert("Please select the stories first.");
  }
})(jQuery);

a bookmarklet to generate the branch name from an open jira story

javascript: (function ($) {
  var branchName = "nothing found" ;
  var story = jQuery(".ghx-fieldname-issuekey a");
  if(story){
    var title = $("[data-field-id='summary']").text();
    var id = story.text();
    
    var translate = {
      "ä": "ae", "ö": "oe", "ü": "ue", "ß": "ss"
    };

    var cleanedTitle = title.toLowerCase().replace(/[öäüß]/g, function(match) { 
      return translate[match]; 
    }).replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_/, "").replace(/_$/, "");

    var cleanedId = id.toUpperCase().replace(/[öäüß]/g, fun...

mtr says "mtr: unable to get raw sockets"

This is because mtr needs to open raw sockets, which it can only do as root:

 $ mtr 8.8.8.8
    mtr: unable to get raw sockets.
    
 $ sudo mtr 8.8.8.8
    Keys:  Help   Display mode   Restart statistics   Order of fields   quit
                                               Packets               Pings
 Host                               Loss%   Snt   Last   Avg  Best  Wrst  StDev
 1. 216.239.48.53                    0.0%    69   24.9   32.0  24.8  88.8    12.5
    64.233.174.55
    209.85.246.205
 2. ???
 3. google-public-dns-a.google...

Use Omniauth/Devise with different Facebook apps (e.g. one for every locale)

To use different Facebook apps for authentication with Devise and OmniAuth:

  1. Add a setup method to Omniauth that dynamically sets the client id and secret:
    # config/initializers/devise.rb
    config.omniauth :facebook, nil, nil, setup: true
  1. Setup a route to your setup method:
    # config/routes.rb
    match '/auth/:provider/setup' => 'sessions#setup'
  1. Use the setup method to set the id and secret options in the request object:
    def setup
      # in this example facebook keys for different site domai...

a bookmarklet to generate the commit message from an open pivotal tracker story

javascript: (function ($) {
    var storyTitles = [];
    var stories = $('div.story .selector.selected').closest('.story');
    var collapsed = true;
    if (stories.length == 0) {
        stories = $('div.story .details').closest('.story');
        collapsed = false;
    }
    stories.each(function () {
        var story = $(this);
        var title = (collapsed ? story.find('.story_name').text() : story.find('.editor.name').val());
        var id = /story_(\d+)/.exec(story.attr('class'))[1];
        var gitptTitle = '[#' + id + '] ' +...

a bookmarklet to generate the branch name from an open pivotal tracker story

javascript: (function ($) {
  var storyTitles = [];
  var story = $('.story .details').closest('.story').first();
  if(story){
    var title = story.find('.editor.name').val();
    var id = /story_(\d+)/.exec(story.attr('class'))[1];
    var storyType = story.find(".story_type .selection").text();
    var gitptTitle = id + '-' + title;
    var translate = {
      "ä": "ae", "ö": "oe", "ü": "ue", "ß": "ss"
    };
    var cleanedTitle = storyType + "/" + gitptTitle.toLowerCase().replace(/[öäüß]/g, function(match) { 
      return translate[...

Dynamically referencing columns in Squeel

Use __send__:

where{__send__(dynamic_column_name) = '42'}

be careful when using admin powers with ClassName.active

Very often when using consul, our scopes look something like:

  power :creatable_books, :updatable_books, :destroyable_books do
    case role
      when :user
        Book.active.where(user_id: @user.id)
    end
  end

This is perfect as new records get created with the right user_id allready set:

001: > Power.new(@user).creatable_books
  => #<Book id: nil, title: nil, description: nil, user_id: 189, created_at: nil, updated_at: nil>
002:>  # Note that the above record has the user_id set.

BUT

When you now implement so...

HELP, the HTML in my I18n strings is escaped!

If there's any HTML in your I18n string, remember to add "_html" to its name.

Gatekeeping: Guide for developer

Note: This has been a private card for some time, because it is heavily tailored to our specific needs and tools. While it will certainly not apply to all (especially larger teams), we thought it might still be helpful as a starting point, and so made it public. Compare also the Gatekeeping: Guide for gatekeeper card.


In order to reduce the number of rejects we get from clients, we want to review all code written before it goes to the staging serv...