Don't name columns like counter_cache columns

ActiveRecord has a feature called counter caching where the containing record in a has_many relationship caches the number of its children. E.g. when you have House has_many :rooms, Rails can cache the number of rooms in House#rooms_count.

Mind that when a model has a column that looks to Rails like a counter-cache column, Rails will apply counter-cache logic to your model, even if you're not using counter caches.

E.g. you have a house with 12 rooms, but `house.r...

Ruby: How to fetch a remote host's TLS certificate

TLS/SSL certificates are often used for HTTPS traffic. Occasionally a service may also use their TLS certificate to support public-key encrypting data (e.g. when it is part of the URI and visible to the user, but contains sensitive information).

Here is how to easily fetch such certificate data.

certificate = Net::HTTP.start('example.com', 443, use_ssl: true) { |http| http.peer_cert }
# => #<OpenSSL::X509::Certificate: subject=#<OpenSSL::X509::Name CN=www.example.org,...>

certificate.public_key
# => #<OpenSSL::PKey::RSA:0x...

Sass partial names must always start with an underscore

Be careful to name any file @imported by SASS with a leading underscore.

SASS files not beginning with an underscore will be rendered on their own, which will fail if they are using variables or mixins defined elsewhere. (For me it broke only in production, which may be due to some settings in SASS-GEM/lib/sass/plugin/rails.rb.)

From the SASS docs:

The underscore lets Sass know that the file is only a partial file and that it should not be generated into a CSS file.

How to make a cucumber test work with multiple browser sessions

Imagine you want to write a cucumber test for a user-to-user chat. To do this, you need the test to work with several browser sessions, logged in as separate users, at the same time.

Luckily, Capybara makes this relatively easy:

Scenario:

Scenario: Alice and Bob can chat
  Given Alice, Bob, and a chat session
  When I am signed in as "Alice"
    And I go to the chat
    And I am signed in as "Bob" [session: bob]
    And I go to the chat [session: bob]
    And I send the message "Hello, this is Alice!"
  Then I should see "Hello, this ...

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...

How to: Validate dynamic attributes / JSON in ActiveRecord

PostgreSQL and ActiveRecord have a good support for storing dynamic attributes (hashes) in columns of type JSONB. But sometimes you are missing some kind of validation or lookup possibility (with plain attributes you can use Active Record's built-in validations and have your schema.rb).

One approach about being more strict with dynamic attributes is to use JSON Schema validations. Here is an example, where a project has the dynamic attributes analytic_stats, that we can use to store analytics from an external measurement tool.

  • A g...

Handling duplicate links with Capybara and Cucumber

Sometimes, you might have duplicate links on a page. Trying to click those links will by default cause Capybara to raise an Ambiguous match error.

If you do not care about which of those links are clicked, you can disable this errors by adding the following meta step:

When(/^(.*) \[allow ambiguous\]$/)do |step_text|
  prior_match_strategy = Capybara.match
  Capybara.match = :first
  step(step_text)
ensure
  Capybara.match = prior_match_strategy
end

Use it with

When I follow "a duplicate link" [allow ambiguous]

Capybara 'fill_in': Ambiguous match for different input names

When you have two inputs, where one contains the name of the other (eg. Name and Name with special treatment), Capybara's fill_in method will fail with the following message:

Ambiguous match, found 2 elements matching visible field "Name" that is not disabled (Capybara::Ambiguous)

You can force Capybara to match exactly what you are typing (which makes your tests better anyways) with match: :prefer_exact:

name = 'Name'
value = 'Bettertest Cucumberbatch'
fill_in(field, with: value, match: :prefer_exact)

Furthermore...

Rspec: around(:all) and around(:each) hook execution order

Summary

  • around(:suite) does not exist.
  • around(:all) runs after before(:all) and before after(:all).
  • around(:each) runs before before(:each) and after after(:each).

As this is not 100% obvious (and not yet documented) it is written down in this card. In RSpec 3 :each has the alias :example and :all the alias :context.

Example

RSpec.configure do |config|
  config.before(:suite) { puts 'BEFORE :suite' }
  config.after(:suite) { puts 'AFTER :suite' }
end

describe 'order of hook execution' do
  aroun...

Always convert and strip user-provided images to sRGB

Debugging image color profiles is hard. You can't trust your eyes in this matter, as the image rendering depends on multiple factors. At least the operation system, browser or image viewer software and monitor influence the resulting image colors on your screen.

When we offer our users the possibility to upload images, they will most likely contain tons of EXIF metadata and sometimes exotic color profiles like eciRGB. We want to get rid of the metadata, as it might contain sensitiv...

How to capture a screen-cast on Linux

Recording

SimpleScreenRecorder

I recommend simplescreenrecorder, it produces an adequate output with only a few clicks. The audio recording contained some static noises, but that might be caused by my microphone.

Recording only a single screen or fixed rectangle is supported. The video quality seems quite grained when using the default settings - I found that using the MKV container, H.264 codec, "0" constant rate factor and "veryslow" preset results in the best video quality.

###...

Jasmine: Test that an object is an instance of a given class

To test that an object was constructed by a given constructor function, use jasmine.any(Klass):

describe('plus()', function() {
  it ('returns a number', function() {
    let result = plus(1, 2)
    expect(result).toEqual(jasmine.any(Number))
  })
})

Also see Expecting objects as method invocation arguments.

Understanding SQL compatibility modes in MySQL and MariaDB

MySQL and MariaDB have an SQL mode setting which changes how MySQL behaves.

The SQL mode value is comprised of multiple flags like "STRICT_TRANS_TABLES, NO_ZERO_IN_DATE". Each flag activates or disables a particular behavior.

The default SQL mode varies widly between versions of MySQL and MariaDB. In general, more recent versions of MySQL and MariaDB have stricter settings than older versions, and MySQL has stricter settings than the more liberal MariaDB.

If your app explodes ...

How to set up SMTP email delivery with a Gmail account

If you want to make your Rails application be capable of sending SMTP emails, check out the action mailer configuration section in the Ruby on Rails guide.

TL;DR you will end up having an smtp_settings hash that looks something like this:

smtp_settings = {
  address: ...,
  domain: ...,
  port: ...,
  user_name: ...,
  password: ...,
  authentication: ...,
  tls: ...,
  enable_starttls_auto: ...,
}

This hash can be set as the `delivery_me...

Howto: Change the keyboard shortcut for the emoji-picker

Im using the terminator terminal with the keyboard shortcut Control+Shift+E for splitting the terminal. I got used to this shortcut.

Yesterday the Ubuntu update seems to have upgraded ibus, which got this emoji picker that also uses Control+Shift+E to open.
You can change this behaviour by opening the ibus setup from the console:

ibus-setup

A window will open and you can delete the shortcut in the emoji tab (Emoji => ... => detele). You're no...

jQuery promises: done() and then() are not the same

jQuery's deferred objects behave somewhat like standard promises, but not really.

One of many subtle differences is that there are two ways to chain callbacks to an async functions.

The first one is done, which only exists in jQuery:

$.ajax('/foo').done(function(html) {
  console.debug("The server responded with %s", html);
});

There is also then, which all promise libraries have:

$.ajax('/foo').then(function(html) {
  console.debug("The server resp...

How to run a small web server (one-liner)

Sometimes you just want to have a small web server that serves files to test something.

Serve the current directory

On Ruby 1.9.2+ you can do the following ("." for current directory).

ruby -run -ehttpd . -p8000

Python 2.x offers a similar way.

python -m SimpleHTTPServer 8000 .

This is the same way with Python 3.x

python -m http.server

In both cases your web server is single-threaded and will block when large files are being downloaded from you.

WEBrick also offers [a simple way](https://stackoverflow.com/quest...