MySQL: CONCAT with NULL fields

In MySQL,

CONCAT('foo', 'bar', NULL) = NULL

the NULL always wins in MySQL.

If you would rather treat NULL as an empty string, use CONCAT_WS (concatenation with separator) instead:

CONCAT_WS('', 'foo', 'bar', NULL) = 'foobar'

PostgreSQL

In PostgreSQL the NULL is not viral in CONCAT:

CONCAT('foo', 'bar', NULL) = 'foobar'

Simple database lock for MySQL

Note: For PostgreSQL you should use advisory locks. For MySQL we still recommend the solution in this card.


If you need to synchronize multiple rails processes, you need some shared resource that can be used as a mutex. One option is to simply use your existing (MySQL) database.

The attached code provides a database-based model level mutex for MySQL. You use it by simply calling

Lock.acquire('string to synchronize on') do
  # non-th...

Javascript: Avoid using innerHTML for unsafe arguments

Make sure that you use the correct property when editing an HTML attribute. Using innerHTML with unsafe arguments makes your application vulnerable to XSS.

  • textContent: Sets the content of a Node (arguments are HTML-safe escaped)
  • innerHTML: Sets the HTML of an Element (arguments are not escaped and may not contain user content)

Hierarchy

This hierarchy gives you a better understanding, where the textContent and the innerHTML properties are defined. It also includes (just for completeness) the innerText property, whi...

Transfer records to restore database entries (with Marshal)

If you ever need to restore exact records from one database to another, Marshal might come in handy.

Marshal.dump is part of the ruby core and available in all ruby versions without the need to install anything. This serializes complete ruby objects including id, object_id and all internal state.

Marshal.load deserializes a string to an object. A deserialized object cannot be saved to database directly as the the dumped object was not marked dirty, thus rails does not see the need to save it, even if the object is not present in...

RSpec: Messages in Specific Order

tl;dr

You can use ordered to ensure that messages are received in a specific order.

Example

expect(ClassA).to receive(:call_first).ordered
expect(ClassB).to receive(:call_second).ordered
expect(ClassB).to receive(:call_third).ordered

#ordered supports further chaining

Example

How to define constants with traits

When defining a trait using the Modularity gem, you must take extra steps to define constants to avoid caveats (like when defining subclasses through traits).

tl;dr

In traits, always define constants with explicit self.

If your trait defines a constant inside the as_trait block, it will be bound to the trait module, not the class including the trait.
While this may seem unproblematic at first glance, it becomes a problem when including trai...

Event delegation (without jQuery)

Event delegation is a pattern where a container element has a single event listener that handles events for all descendants that match a CSS selector.

This pattern was popularized by jQuery that lets you do this:

$('.container').on('click', '.message', function(event) {
  console.log("A message element was clicked!")
})

This technique has some advantages:

  1. When you have many descendants, you save time by only registering a single listener.
  2. When the descendants are changed dynamic...

Spreewald development steps

Our gem spreewald supports a few helpers for development. In case you notice errors in your Cucumber tests, you might want to use one of them to better understand the underlying background of the failure. The following content is also part of the spreewald's README, but is duplicated to this card to allow repeating.

Then console

Pauses test execution and opens an IRB shell with current cont...

How to (and how not to) design REST APIs · stickfigure/blog Wiki

In my career, I have consumed hundreds of REST APIs and produced dozens. Since I often see the same mistakes repeated in API design, I thought it might be nice to write down a set of best practices. And poke fun at a couple widely-used APIs.

Much of this may be "duh", but there might be a few rules you haven't considered yet.

RSpec: Composing a custom matcher from existing matchers

When you find similar groups of expect calls in your tests, you can improve readability by extracting the group into its own matcher. RSpec makes this easy by allowing matchers to call other matchers.

Example

The following test checks that two variables foo and bar (1) have no lowercase characters and (2) end with an exclamation mark:

expect(foo).to_not match(/[a-z]/)
expect(foo).to end_with('!')

expect(bar).to_not match(/[a-z]/)
expect(bar).to end_with('!')

We can extract the repeated matcher chains into a custom m...

Ruby: Using `sprintf` to replace a string at fixed named references

The sprintf method has a reference by name format option:

sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) # => 1 : 2.000000
sprintf("%{foo}f", { :foo => 1 })                      # => "1f"

The format identifier %<id> stands for different data types to be formatted, such as %f for floats:

sprintf('%f', 1) # => 1.000000

Example:

This is quite useful to replace ...

`simple_format` does not escape HTML tags

simple_format ignores Rails' XSS protection. Even when called with an unsafe string, HTML characters will not be escaped or stripped!

Instead simple_format calls sanitize on each of the generated paragraphs.

ActionView::Base.sanitized_allowed_tags
# => #<Set: {"small", "dfn", "sup", "sub", "pre", "blockquote", "ins", "ul", "var", "samp", "del", "h6", "h5", "h4", "h3", "h2", "h1", "span", "br", "hr", "em", "address", "img", "kbd", "tt", "a", "acrony...

How to use Rails URL helpers in any Ruby class

If you have any class which requires access to some path methods generated by your routes. Even though you could technically include Rails.application.routes.url_helpers, this may include way too many methods and even overwrite some class methods in the worst case.

Instead, most of the time the following is advised to only make the desired methods available:

class Project
  delegate :url_helpers, to: 'Rails.application.routes'

  def project_path
    url_helpers.project_path(self)
  end
end

Using Rationals to avoid rounding errors in calculations

Ruby has the class Rational which allows you to store exact fractions. Any calculation on these variables will now use fractional calculations internally, until you convert the result to another data type or do a calculation which requires an implicit conversion.

Example use case:

Lets say you want to store the conversion factor from MJ to kWh in a variable, which is 1/3.6. Using BigDecimals for this seems like a good idea, it usually helps with rounding errors over a float, but the...

List of default browser stylesheets

Even when you app has no CSS at all, you still inherit a default user agent stylesheet from your browser.

These default styles vary from browser to browser:

Links found in A look at CSS Resets in 2018.

A reasonable default CSP for Rails projects

Every modern Rails app should have a Content Security Policy enabled.

Very compatible default

The following "default" is a minimal policy that should

  • "just work" for almost all applications
  • give you most of the benefits of a CSP

In your config/initializers/content_security_policy.rb, set

Rails.application.config.content_security_policy do |policy|
  policy.object_src :none
  policy.script_src :unsafe_eval, :strict_dynamic, :https # Browsers with support for "'strict-dynamic'" will ignore "https:"
  po...

Know your Haml comments

There are two distinct ways of commenting Haml markup: HTML and Ruby.

HTML comments

This will create an HTML comment that will be sent to the client (aka browser):

/= link_to 'Example', 'www.example.com'

This produces the following HTML:

<!-- = link_to 'Example', 'www.example.com' -->

Only use this variant if you need the comment to appear in the HTML.

Ruby comments

This will comment code so it will not be sent to the client:

-# = link_to 'foo'

99% of the time you'll be adding notes f...

Merging two arbitrary ActiveRecord scopes

(Rails has a method ActiveRecord::Relation#merge that can merge ActiveRecord scopes. However, its behavior has never been clear, and in Rails 7 it still discards conditions on the same column by the last condition. We discourage using #merge!)

The best way to merge ActiveRecord scopes is using a subquery:

scope_a.where(id: scope_b)

It is a little less concise than #merge, but unambiguous.

Example

Assume a model where a deal has many documents:

class Deal < ApplicationRecord
  has_many :...

Testing if two date ranges overlap in Ruby or Rails

A check if two date or time ranges A and B overlap needs to cover a lot of cases:

  1. A partially overlaps B
  2. A surrounds B
  3. B surrounds A
  4. A occurs entirely after B
  5. B occurs entirely after A

This means you actually have to check that:

  • neither does A occur entirely after B (meaning A.start > B.end)
  • nor does B occur entirely after A (meaning B.start > A.end)

Flipping this, A and B overlap iff A.start <= B.end && B.start <= A.end

The code below shows how to implement this in Ruby on Rails. The example is a class `Interv...

Zeitwerk: How to collapse folders in Rails

All direct child directories of app are automatically added to the eager- and autoload paths. They do NOT create a module for namespacing. This is intuitive, since there normally is no module Model, or module Controller. If you want to add a new base directory, there's no additional config needed.

Example

app
├── controllers
├── helpers
├── inputs # No config needed 
├── mailers
├── models
├── uploaders # No config needed
├── util # No config needed
└── workers # No config needed

Sometimes it's handy to group files wit...

How to: Upgrade CarrierWave to 3.x

While upgrading CarrierWave from version 0.11.x to 3.x, we encountered some very nasty fails. Below are the basic changes you need to perform and some behavior you may eventually run into when upgrading your application. This aims to save you some time understanding what happens under the hood to possibly discover problems faster as digging deeply into CarrierWave code is very fun...

Whitelists and blacklists

The following focuses on extension allowlisting, but it is the exact same thing for content type allowlisting with the `content_ty...

Google Chrome: How to restore the old downloads bar

The old Chrome downloads bar had several advantages over the new subtle downloads dropdown:

  • see all (many, at least) downloads at once and see their progress
  • downloads can be opened with a single click
  • drag them back into another web page to upload them again, with no extra clicks required

How to get it back

  1. Go to chrome://flags/#download-bubble
  2. Click the dropdown and change it to Disabled

They say the flag might be removed in the future, but for now it gets the downloads bar back.

Delivering Carrierwave attachments to authorized users only

Preparation

To attach files to your records, you will need a new database column representing the filename of the file. To do this, add a new migration (rails g migration <name>) with the following content:

class AddAttachmentToNotes < ActiveRecord::Migration[6.0]
  def change
    add_column :notes, :attachment, :string
  end
end

Don't forget to rename the class and change the column details to fit your purpose. Run it.

1) Deliver attachments through Rails

The first way is to store your Carrierwave attachments not ...

Geordi hints

Reminder of what you can do with Geordi.

Note: If you alias Geordi to something short like g, running commands gets much faster!
Note: You only need to type the first letters of a command to run it, e.g. geordi dep will run the deploy command.

geordi deploy

Guided deployment, including push, merge, switch branches. Does nothing without confirmation.

geordi capistrano

Run something for all Capistrano environments, e.g. geordi cap deploy

geordi setup -t -d staging

When you just clon...