Devise: Invalidating all sessions for a user

Background information about session storage in Rails

Rails has a default mechanism to store the session in the CookieStore. This is a cookie which holds the entire user session hash in the browser. This cookie is serialized, encoded with base64, and signed.

How Devise handles authentication

Devise uses this CookieStore. To track a users session, a salt is stored in the session ...

ActiveRecord::Store: migrate data in store

When you need to store structured data (like Ruby hashes) in a single database column with ActiveRecord, a simple way is to use PostgreSQL's jsonb columns. ActiveRecord will automatically serialize and deserialize your Hash to and from JSON, and you can index JSON paths for fast reads.

As an alternative, ActiveRecord::Store offers a way to store hashes in a single database column. This card will show you how to migrate those hashes in an ActiveRecord::Migration by example:
...

Rails: Including HTML in your i18n locales

TL;DR

Append your locale keys with _html to have them marked as html_safe and translate them with = t('.text_html').

When you're localizing a Rails application, sometimes there is this urge to include a little HTML. Be it some localized link, or a set of <em> tags, you'd like to have it included in the locale file. Example:

# Locale file
en:
  page:
    text: 'Please visit our <a href="https://www.corporate.com/en">corporate website</a> to learn more about <em>the corporation</em>.'
    
# HAML
= t('.text')
    
# D...

ActionMailer: How to send a test mail directly from the console

If your rails application is unable to send mails, it might be useful to debug your settings using the rails console. Here is a snippet that shows the current settings and lets you send a test mail directly from the console:

mailer = ActionMailer::Base.new

# check settings:
mailer.delivery_method # -> :smtp
mailer.smtp_settings # -> { address: "localhost", port: 25, domain: "localhost.localdomain", user_name: nil, password: nil, authentication: nil, enable_starttls_auto: true }

# send mail:
mailer.mail(from: 'sender@example.com', ...

PostgreSQL: How to show table sizes

When you have a large PG database, you may want to find out which tables are consuming the most disk space.
You can easily check this using the following SQL statement from the PostgreSQL wiki.

SELECT nspname || '.' || relname AS "relation",
    pg_size_pretty(pg_total_relation_size(C.oid)) AS "total_size"
  FROM pg_class C
  LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
  WHERE nspname NOT IN ('pg_catalog', 'information_schema')
    AND C.relkind <> 'i'
    AND nspname !~ '^pg_toast'
  ORDER BY pg_tot...

User-defined Order in SQL

The attached article explains options you have to store the order of items in a database table.

The simplest solution of course is to use a position column. However the author explores some alternatives where you don't need to update multiple rows when you move a single item.

How to resize your boot partition when there is an encrypted partition after it

Boot partitions from installations prior to the 16.04 era are terribly small. When you install updates and encounter errors due to a full /boot partition, consider risizing it.

If you can't do the steps described below, ask someone experienced to help you out.
This has worked 100% so far. 1 out of 1 tries. ;)

Scenario A: There is unassigned space on your physical drive

When there is some unpartitioned space on your drive, increasing the size of /boot is actually very easy (even though the list below is rather long). It only takes a...

Don't sum up columns with + in a SQL query if NULL-values can be present.

Don't sum up columns with + in a sql-query if NULL-Values can be present.

MySQL and PostgreSQL cannot sum up NULL values with the + value. The sum value will be NULL.

MySQL:

mysql> select 1 + 2 + 3;
+-----------+
| 1 + 2 + 3 |
+-----------+
|         6 |
+-----------+
1 row in set (0,00 sec)

mysql> select 1 + NULL + 3;
+--------------+
| 1 + NULL + 3 |
+--------------+
|         NULL |
+--------------+
1 row in set (0,00 sec)

Postgres:


test_database=# select 1 + 2 + 3;

 ?column? 
----------
        6
(1 row)

t...

Geordi 1.9 released

New features:

geordi delete_dumps [directory]

Recursively search for files ending in *.dump and offer to delete those. When no argument is given, two default directories are searched for dump files: the current working directory and ~/dumps (for dumps created with geordi).

geordi drop_databases

Delete local MySQL/MariaDB and Postgres databases that are not whitelisted.

Authentication is handled via PAM for Postgres and MariaDB, via .my.cnf with fallback to mysql -p for MySQL. Different connection methods can be chosen via ...

Running Rails 2 apps with modern MariaDB SQL server

You might have some trouble running a Rails LTS 2 app with MySQL 5.7.

If you don't want to hack Mysql 5.6 into your modern Ubuntu or use the MySQL sandbox, you might want to try MariaDB 10.x.

MariaDB 10.x should work with both old and new Rails applications.

[Switch to MariaDB](https://makandracards.com/makandra/468343-how-...

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

Store MySQL passwords for development

On your local system that only hosts non-critical development data and only you have access to, you can store MySQL's root password in your home directory so you can use mysql commands without prompt for passwords, i.e. when doing batch processing.

Of course, this has security implications. The password must be stored in plain text, so this method is out of the question if there's any confidential data in your databases. Assuming diligent screen-locking, an encrypted hard disk and correct permissions set on your credential file, it shoul...

Advantages of using appname.daho.im:3000 over localhost:3000

Running rails server will start a local server that you can access via http://localhost:3000.

When you are working on multiple web apps, they will likely set cookies with generic names on localhost. This is annoying, since you will sign out your current user whenever you switch to another app.

A better way is to use our own daho.im service. All daho.im subdomains resolve to your local IP (127.0.0.1). That means you can use a different hostname for different apps, and you will stay logged in in each app:

http://foo-ap...

PostgreSQL: Upgrading your user to a superuser

Your default postgres user is named like your linux user. That default user has limited access privileges, which can cause issues such as:

  • DatabaseCleaner needs to disable foreign key constraints before it can wipe the database.
  • Importing a remote dump with geordi
  • Asking Postgres to show the storage path of a database

Doing these things without a superuser will show a Postgres error or (in Ruby) raise PG::InsufficientPrivilege.

To do so, the application's PostgreSQL user must be a superuser. ...

Mysql::Error: BLOB/TEXT column can't have a default value

mysql> SELECT @@global.version;
+------------------+
| @@global.version |
+------------------+
| 5.6.30           |
+------------------+
1 row in set (0,00 sec)

MySQL 5.6 Reference Manual says "BLOB and TEXT columns cannot have DEFAULT values".

If you want to run migrations in development here are two variants which might help. If you are not sure about the side effects (e.g. your application is broken when it doesn't set additional default values on application side, too...

Chrome: Making high-resolution website screenshots without add-ons

If you want to make a screenshot of a website that works well in print or on a high-DPI screen (like Apple Retina displays), here is how you can capture a high-resolution screenshot.

You can do this without an addon:

  • Open the website
  • If you have multiple monitoros:
    • Resize the Chrome window so it covers multiple monitors (in Linux you can hold ALT and resize by dragging with the right mouse button)
    • Zoom into the page using CTRL + and CTRL - so it covers most of the window area. Leave a little padding on the left and right so...

Decide whether cronjobs should run on one or all servers

Understanding your type of cronjob

Some cronjobs must only run on a single server. E.g. when you run nightly batch operations on the database, it should probably run on a single server. Running it on multiple servers would likely result in deadlocks or corrupt data.

Some cronjobs must always run on all servers. E.g. starting a sidekiq process on reboot.

Configuring whenever

If not configured otherwise, cronjobs defined in whenever's `s...

Ruby: Using all? with empty collection

Enumerable#all? returns true for an empty collection. This totally makes sense but you have to think about it when making assumptions on relations which might be empty.

[].all?(&:will_never_be_called_here) => true

Example with empty collection

class Researcher < ActiveRecord::Base
  has_many :papers
end

class Paper
  validates :topic, inclusion: { in: ['computer_science', 'mathematics', 'economy'] }
end

Easy goal: Delete all researches who write onl...

Font Awesome 5 migration guide

Font Awesome version 5 changed some icon names, and introduces new prefixes fab, far, and fas.

There is a JavaScript shim that you can use as a "quick fix". It allows you to keep v4 icon names on v5.

The linked page includes details on using that, and a migration guide including a list of icon renames.

Carrierwave: Deleting files outside of forms

TL;DR Use user.update!(remove_avatar: true) to delete attachments outside of forms. This will have the same behavior as if you were in a form.


As you know, Carrierwave file attachments work by mounting an Uploader class to an attribute of the model. Though the database field holds the file name as string, calling the attribute will always return the uploader, no matter if a file is attached or not. (Side note: use #present? on the uploader to check if the file exists.)

class User < ApplicationRecord
  mount :avatar, ...

RSpec: How to check that an ActiveRecord relation contains exactly these elements

To check which elements an ActiveRecord relation contains use the contain_exactly matcher.

describe User do
  let!(:admin) { create(:user, role: 'admin') }
  let!(:customer) { create(:user, role: 'customer') }
  
  subject(:users) { User.where(role: 'admin') }
  
  # Recommended (The error output is most helpful)
  it { expect(users).to contain_exactly(admin) }
  
  # Other options
  it { expect(users).to eq([admin]) }
  it { expect(users.pluck(:id).to eq([admin.id]) }
end

In case you have an `ActiveRecord::AssociationRelati...

Rails and Postgres: How to test if your index is used as expected

This is a small example on how you can check if your Postgres index can be used by a specific query in you Rails application. For more complex execution plans it might still be a good idea to use the same path of proof.

1. Identify the query your application produces

query = User.order(:last_name, :created_at).to_sql
puts query
# => SELECT "users".* FROM "users" ORDER BY "users"."last_name" ASC, "users"."created_at" ASC

2. Add an index in your migration and migrate

add_index :users, [:last_name, :created_at]...

Form letters with LibreOffice Writer

This is painful. Consider using Microsoft Office or switching careers. If you need to write < 20 letters consider doing it manually.

So you didn't listen and here it comes:

  1. Ignore the Mail Merge Wizard. It will crash or destroy your document.
  2. Export your addresses, recipient names, etc. as a .ods spreadsheet (.xls, .xlsx, .ods). Use any columns that work for you, but be consistent. I like to use one column for the address, one column for the salutation line.
  3. Import the spreadsheet as an address book source: *Tools => Add...

Error during Rails 5 upgrade: Environment data not found in the schema

This error is raised because your old database does not have a configured environment yet, which Rails 5 enforces.

If this error occurs while migrating your parallel test databases, make sure to update the parallel_tests gem first: current versions fix this. If you're still using Cucumber < v3, the latest version of parallel_tests will be 2.18.0.