Don't assign time values to date attributes

Do not pass times to date attributes. Always convert times to dates when your application uses time zones.

Background

A time-zoned Time attribute on a Rails record is converted to UTC using to_s(:db) to be stored, and converted back into the correct time zone when the record is loaded from the database. So when you are not on UTC, time objects will be converted as follows.

>> Time.current
=> Fri, 15 Mar 2013 11:56:03 CET +01:00
>> Time.current.to_s(:db)
=> "2013-03-15 10:56:03" # This is now UTC

Problem

That will...

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

CarrierWave: Processing images with libvips

When you write your next CarrierWave uploader, consider processing your images with libvips instead of ImageMagick.

Reasons for libvips

There are several upsides to using libvips over ImageMagick:

How to find child nodes that match a selector with JavaScript

Using querySelector or querySelectorAll in JavaScript, you can easily find descendants of a node that match a given selector.

But what if you want to find only children (i.e. direct descendants) of an element?
Easy: use :scope. It references the element on which DOM API methods are being called:

element.querySelectorAll(':scope > .your-selector')

Example

Consider this HTML

<body>
  <div id="container1">
    <div id="container1a">foo</div>
    <div id="container1b">bar</div>
    <div id="container1c">baz</...

Code splitting in esbuild: Caveats and setup

Code splitting is a feature of esbuild that can keep huge libraries out of the main bundle.

How code splitting works

Like Webpack esbuild lets you use the await import() function to load code on demand:

// application.js
const { fun } = await import('library.js')

fun()

However, esbuild's code splitting is disabled by default. The code above would simply inline (copy) `l...

RubyMine and Rubocop: Performing safe autocorrects on save

  • Ctrl + Alt + S > search "rubocop on save"
  • Under "Inspections", check the highlighted box on rubocop -a

Caveat: This adds a little time overhead to saving. When you're editing many files at once (e.g. using "Replace All"), this may be inacceptable.

RubyMine: Fixing "Rubocop returned exit code -1. See the logs for details"

When RubyMine reports Rubocop returning "exit code -1", upgrading Rubocop can be the fix:

gem install rubocop

"The logs" can be accessed with Ctrl + Shift + A > Show log in (Files). This opens your file manager at the IDEA log location; the log file is called "idea.log".
If your operating system supports it, right click into the file manager > Open in Terminal. There run tail -f idea.log to follow the log.

Create and send any HTTP request using the Postman request builder

Talking with APIs makes more fun using Postman. As an alternative you can also use command line tools like cURL.

Image

snap install postman

How does it help me?

  • Editing multiline JSON bodies is much more comfortable than in the terminal
  • Saving named requests in a collection (can be shared with others)
  • Syntax highlighting when writing JSON bodies
  • History with all my requests
  • Multiple environments
  • Cookie manager

We now have our own memoization gem "Memoized"

We forked trusty memoizer to make two changes:

  1. Memoized methods now preserve their arity. Previously all memoized methods had an arity of -1.
  2. Memoized methods are now faster at runtime. This will only be noticable if you call a memoized methods many times in the same request.

We published our fork as a new gem named memoized.

memoized is API-compatible to memoizer, you just need to include Memoized instead of `M...

Cucumber: Identifying slow steps that drag down your test speed

In most projects I know, Cucumber test suite speed is not an issue. Of course, running 350 features takes its time, but still each test for itself is reasonably fast. There is nothing you can do to fundamentally speed up such a test (of course, you should be using parallel_tests).

However, in projects that go beyond clicking around in a web GUI and checking results, there might be various measures to speed things up. Katapult tests for example could be sped up more than 4 times by re...

Balance your texts today with text-wrap: balance

So you have a heading that is just barely wider than the container it should fit into, and it wraps a single word to a new line and it's not really pretty?
Cry no more, for you can use text-wrap: balance today to fix that. At least in some browsers.

When browsers encounter a text-wrapping element with text-wrap: balance style, they will try breaking to a new line sooner, if it balances out the width of lines.

text-wrap: unset text-wrap: balance
Image ![Image](/makandr...

Checklist for Implementing Design

We have a long-standing checklist for merge requests. However, it hardly matches the intricate requirements for design. This checklist fills the gap.

Before starting implementing, look at all designs: are there components similar to yours? Have they already been implemented? Can you build on this prior art when implementing yours?

Checklist: I confirm my design implementation

  • has been tested manually by me
  • adheres to the code style of the project (e.g. BEM)
  • avoids "magic numbers" (don't say e.g. ...

Ruby: alias_method conflicting with prepend

alias_method makes a copy of a method. This works fine until the same method is overridden using prepend. If the prepend is executed after alias_method, you'll either see an infinite loop, or loose the prepended functionality.

Solution

Your options are:

  • Ensure prepend happens before alias_method
  • If you can control the alias_method invocation: rewrite to the modern & better prepend
  • If you can only control the prepend invocation: rewrite to the legacy alias_method

Git: Splitting up changes into several commits

Splitting up commits makes the process of reviewing often easier, since you can create several merge requests or review every commit one by one.

So when you find out that you have portions of the code that you initially didn't intend to change or when you do some refactoring along the current changes, you can use one of the following processes to split up the changes into several commits in a logical order:

#1 Splitting up the last n commits into m commits
#2 Adding changes to a previous commit
2.1 While adding new changes
2.2 S...

Best practice: How to manage versions in a package.json

It most cases it's not necessary to add a version constraint next to your packages in the package.json. Since all versions are saved in a lockfile, everyone running yarn install will get exactly the same versions. Yarn saves this lockfile as yarn.lock and npm as package-lock.json.

There are some exceptions, where you can consider adding a version constraint to the package.json:

  • You are not checking the lockfile into version control (not recommended)
  • A specific package has a bug in a more recent version
  • You want to ensure no...

Best practice: How to manage versions in a Gemfile

It most cases it's not necessary to add a version constraint next to your gems in the Gemfile. Since all versions are saved in the Gemfile.lock, everyone running bundle install will get exactly the same versions.

There are some exceptions, where you can consider adding a version constrain to the Gemfile:

  • You are not checking in the Gemfile.lock into the version control (not recommended)
  • A specific gem has a bug in a more recent version (adding a comment for the reason is highly recommended)
  • You want to ensure no one upgrade...

RSpec 3 argument constraints use weak equality

If you expect method calls in RSpec 3, be aware that the argument matchers use very liberal equality rules (more like === instead of ==).

For example:

expect(subject).to receive(:foo).with(MyClass)

subject.foo(MyClass)      # satisfies the expectation
subject.foo(MyClass.new)  # also satisfies the expectation

expect(subject).to receive(:bar).with(/regex/)

subject.bar(/regex/)      # satisfies the expectation
subject.bar('regex')      # also satisfies the expectation

This is usually not an issue, except when your method ...

Rails < 5: How to get after_commit callbacks fired in tests

If you use transactional_fixtures or the database_cleaner gem with strategy :transaction, after_commit callbacks will not be fired in your tests.

Rails 5+

Rails 5 has a fix for this issue and no further action is needed.

Rails 3, Rails 4

Add the gem test_after_commit to your test group in the Gemfile and you are done. You don't need to change the database strategy to deletion (wh...

ActiveRecord: Creating many records works faster in a transaction

When you need to insert many records into the same table, performance may become an issue.

What you can do to save time is to open a transaction and save multiple records within that transaction:

transaction do
  500.times { Model.create! }
end

Although you will still trigger 500 INSERT statements, they will complete considerably faster.

When I tried it out with a simple model and 500 iterations, the loop completed in 1.5 seconds vs. 6 seconds without a transaction.

Alternative

Another fast way to insert many ...

Local deployment after pipeline succeeds

If you have a fully functional CI pipeline but no CD, you might find yourself frequently waiting for CI (with "merge after pipeline succeeds") just to perform the deployment.

The following command waits for the next commit that lands on the current branch (should be main or similar) and proceeds to deploy staging afterwards:

alias await-deployment='watch -g git pull && bundle exec cap staging deploy'

Note

Use at your own risk.
You could be deploying code from someone else that was pushed to the same branch in the meantime.

How to configure case insensitive git output

Git commands like diff use the less binary for their output representation.

I often find myself searching for strings like todo, then switching to the case-insensitive mode (-i) and re-doing my search.
Today I figured out that you can configure git to show case insensitive diffs every time:

git config --global core.pager 'less -i'

Geordi 9.6.0 released: new "did you know?" feature

Geordi will now suggest related commands and options (hand-picked). If a command has suggestions, a single suggestion is printed with a 10% probability after a successful command.

Find Where a Rake Task is Defined

You can use rake --where task to find the source location that defines task:

bundle exec rake --where assets:precompile
rake assets:precompile              /home/henning/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/precompiled_assets-0.2.1/lib/precompiled_assets/tasks/assets.rake:5:in `block in <main>'

Vim: Simple way to edit several lines at once at the same cursor position

Within Vim do the following:

  • Move cursor to the first starting line where you want to start editing
  • ctrl + v to enter select mode to select all characters in one column
  • Move the cursor vertically down until you selected the last line
  • shift + i to got into "multiple" insert mode
  • Do all the required editings
  • Use the ESC-character exit insert mode
  • Press ESC-character to apply all changes

Hint

This does not work with deleting and editing at once

  • If you first want to delete the content, can also use the select mode ...