View

Testing webpages globally (as in "around the globe")

These tools help you in checking websites globally:

DNS Checker
This tool allows for global DNS propagation checking.
GeoScreenshot
This tool takes screenshots of a given URL from various locations across the world.

Webmock's hash_including doesn't parse query values to string

Webmocks hash_including is similar to RSpec::Mocks::ArgumentMatchers#hash_including. Be aware that hash_including (webmock v3.0.1) doesn't parse integer values to String.

Without hash including you would say:

uri = URI('http://example.com/?foo=1&bar=2')
stub_request(:get, 'example.com').with(query: {foo: 1, bar: 2})
Net::HTTP.get(uri) # ===> Success

If you only want to check if foo is present you can use hash_including:

```
uri = URI('http://example.com/?foo=1&bar=2')
stub_request(:get, 'example.com').with(query: hash_i…

Repeats

Use Time.current / Date.current / DateTime.current on projects that have a time zone

This ancient card is no longer entirely correct for newer Railses and was rewritten.

Basically, you now need to know if your project uses a "real" time zone or :local, and if config.active_record.time_zone_aware_attributes is set to false or not.

  • With time zones configured, always use .current for Time, Date, and DateTime.

    ActiveRecord attributes will be time-zoned, and .current values will be converted properly when written to the database.
    Do not use Time.now and friends. Timezone-less objects will not be convert…

External content

Standard Gems

Ruby's standard library is in the process of being gemified. It will soon - Ruby 2.5 - consist of RubyGems, which can be updated independently from Ruby.

This might mean smoother Ruby upgrades in the future. If breaking API changes happen in standard gems, we can update these before upgrading Ruby.

RSpec: Stubbing a method that takes a block

If you stub a method or set expectations with should_receive these stubbed methods may also yield blocks. This is handy if the returning object is receiving a block call.

Consider this, where you cannot say and_return [] because of the block:

def crawl_messages
  Message.find_in_batches do |messages|
    messages.each(&:crawl)
  end
end

It works similar to and_return – just use and_yield:

describe '#crawl_messages' do
  it 'should proc...

Middleman for Rails Developers

Middleman is a static page generator that brings many of the goodies that Rails developers are used to.

Out of the box, Middleman brings Haml, Sass, helpers etc. However, it can be configured to do even better. This card is a list of improvement hints for a Rails developer.

Gemfile

Remove tzinfo-data and wdm unless you're on Windows. Add these gems:

```
gem 'middleman-livereload'
gem 'middleman-sprockets' # Asset pipeline!

gem 'bootstrap-sass' # If you want to use Bootstrap

gem 'byebug'

gem 'capistrano'
gem 'capistrano-mid…

How to define height of a div as percentage of its variable width

This is useful if, for example, you want to use a background-image that has to scale with the width and the div should only have the height of the picture.

html:

<div class="outer">
  <div class="inner">
  </div>
</div>

css:

.outer {
  width: 100%;
  background-image: image-url('background.png');
  background-size: cover;
}
  
.inner {
  padding-top: 60%;
}

How does it work?

There are several CSS attributes that can handle values as percentage. But they use different other attributes as "reference value…

Listing all gems on a private gem server

You can use gem list to list all gems available from a remote gem server:

gem list -r --clear-sources -s 'https://user:password@gemserver.tld/'

This is useful to debug cases where Bundler complains of a gem existing in more than one gem source.

Repeats

Understanding race conditions with duplicate unique keys in Rails/MySQL

validates_uniqueness_of is not sufficient to ensure the uniqueness of a value. The reason for this is that in production, multiple worker processes can cause race conditions:

  1. Two concurrent requests try to create a user with the same name (and we want user names to be unique)
  2. The requests are accepted on the server by two worker processes who will now process them in parallel
  3. Both requests scan the users table and see that the name is available
  4. Both requests pass validation and create a user with the seemingly available name…
External content

HTTP/2 push is tougher than I thought - JakeArchibald.com

TLDR: Browser implementations of HTTP/2 push are horrible. You might end up with worse performance than without pushing. However, the article includes a great explanation of how HTTP/2 push are supposed to integrate with browser APIs.

Repeats

Differences between transactions and locking

Web applications can be used by multiple users at the same time. A typical application server like Passenger has multiple worker processes for a single app. In a distributed deployment setup like we use at makandra you will even have multiple application servers, each with their own worker pool.

This means that your code needs to deal with concurrent data access. The two main tools we use to cope with concurrency are database transactions and distributed locks. These two are not interchangeable. You ca…

Capistrano 3: How to deploy when a firewall blocks your git repo

Sometimes, through some firewall or proxy misconfiguration, you might have to deploy to a server that cannot access the git repository. You should have this fixed, but as a temporary workaround, you can tunnel git access through SSH.

Follow these steps:

  1. Log in to the remote server and delete the cached repo (in project_root/repo).
  2. Open a separate SSH connection for each target server and forward an SSH port like this:

    ssh deploy-user@server -R 1222:git.host:22

  3. Set the repo url in your deploy.rb to `ssh://git@loca…

Git: rebase dependent feature branch after squash

This card will show you how to use git rebase --onto without confusion.

Use case:

You've got two feature branches (one and two), where two depends on one. After code review the commits of branch one are squashed. Thus the commit history this branch has changed. Branch two however didn't change. To make the branches share the same commit history again you will have to rebase and replay the additional commits of branch two onto branch one.

Solution:

The easiest way for me to correctly use `git rebase –o…

Repeats

Webmock normalizes arrays in urls

Typhoeus has a different way of representing array params in a get request than RestClient.

Typhoeus: http://example.com/?foo[0]=1&foo[1]=2&foo[2]=3
RestClient: http://example.com/?foo[]=1&foo[]=2&foo[]=3

Webmock normalizes this url when matching to your stubs, so it is always http://example.com/?foo[]=1&foo[]=2&foo[]=3. This might lead to green tests, but in fact crashes in real world. Rack::Utils.build_nested_query might help to build a get re…

Repeats

How to use the Capistrano shell to execute commands on servers

Capistrano brings the shell command which allows you to run commands on your deployment targets.
There is also invoke to run a command directly from your terminal.

Both commands allow running Capistrano tasks or shell commands, and scope to individual machines or machine roles.

cap shell

Basics

First of all, spawn a Capistrano shell (we're using the multistage extension here):

$ cap staging shell

In your "cap" shell you can now run Capistrano tasks by prepending an exclamation mark. For example:

cap> !deploy:revisi...
Repeats

About Ruby's conversion method pairs

Ruby has a set of methods to convert an object to another representation. Most of them come in explicit and implicit flavor.

explicit implicit  
to_a to_ary  
to_h to_hash to_h is only available in Ruby 2+
to_s to_str  
to_i to_int  

There may be even more.

Don't name your methods like the implicit version (most prominently to_hash) but the like the explicit one.

Explicit conversion

Explicit conversion happens when requesting it, e.g. with the splat opera…

Middleman: Use pretty URLs without doubling requests

By default Middleman generates files with a .html extension. Because of this all your URLs end in /foo.html instead of /foo, which looks a bit old school.

To get prettier URLs, Middleman lets you activate :directory_indexes in config.rb. This makes a directory for each of your pages and puts a single file index.html into it, e.g. /foo/index.html. This lets you access pages with http://domain/foo.

Don't double your requests!

Unfortunately you are now forcing every br…

Quickly printing data in columns on your Ruby console

Dump this method into your Ruby console to quickly print data in columns. This is helpful for e.g. comparing attributes of a set of Rails records.

def tp(objects, *method_names)
  terminal_width = `tput cols`.to_i
  cols = objects.count + 1 # Label column
  col_width = (terminal_width / cols) - 1 # Column spacing

  Array(method_names).map do |method_name|
    cells = objects.map{ |o| o.send(method_name).inspect }
    cells.unshift(method_name)

    puts cells.map{ |cell| cell.to_s.ljust(col_width) }.join ' '
  end

  nil
end

Usag…

View
3311 cards