How to turn images into inline attachments in emails

Not all email clients support external images in all situations, e.g. an image within a link. In some cases, a viable workaround is to turn your images into inline attachments.

Note

Rails provides a simple mechanism to achieve this:

This documentation makes it look like you have to care about these attachments in two places. You have to create the attachment in t...

Carrierwave: Custom file validations inside custom Uploaders

Carrierwave's BaseUploader can have some validations that you can use by overriding a certain method, which's expected name is hard coded. A popular example is extension_allowlist, which returns an array of strings and let's you only upload files that have a filename with an extension that matches an entry in that array. Another useful validation can be size_range, which gives you a little bit of control over how your storage gets polluted.

This is often good enough, but some times you need to validate special cases.

Validations t...

Rails: Encrypting your database information using Active Record Encryption

Since Rails 7 you are able to encrypt database information with Active Record. Using Active Record Encryption will store an attribute as string in the database. And uses JSON for serializing the encrypted attribute.

Example:

  • p: Payload
  • h: Headers
  • iv: Initialization Vector
  • at: Authentication Tag
{ "p": "n7J0/ol+a7DRMeaE", "h": { "iv": "DXZMDWUKfp3bg/Yu", "at": "X1/YjMHbHD4talgF9dt61A=="} }

Note this before encrypting attributes with Active Record:
...

How to view a file from another branch

Just run git show branch:file. Examples:

git show HEAD~:bin/command
git show origin/master:../lib/version.rb

When you want to format only line breaks, you probably do not want `simple_format`

For outputting a given String in HTML, you mostly want to replace line breaks with <br> or <p> tags.
You can use simple_format, but it has side effects like keeping some HTML.

If you only care about line breaks, you might be better off using a small, specialized helper method:

def format_linebreaks(text)
  safe_text = h(text)
  paragraphs = split_paragraphs(safe_text).map(&:html_safe)

  html = ''.html_safe
  paragraphs.each do |paragraph|
    html << content_tag(:p, paragraph)
  end
  html
end

Full di...

git: find the version of a gem that releases a certain commit

Sometimes I ran across a GitHub merge request of a gem where it was not completely obvious in which version the change was released. This might be the case for a bugfix PR that you want to add to your project.

Git can help you to find the next git tag that was set in the branch. This usually has the name of the version in it (as the rake release task automatically creates a git tag during release).

git name-rev --tags <commit ref>

Note

The more commonly used git describe command will return the last tag before a c...

Rails: Accessing helper methods from a controller

In Rails 5+ you can access a helper from a controller using the helpers method:

# Inside a controller action
helpers.link_to 'Foo', foo_path

In older Rails versions you can use view_context instead:

# Inside a controller action
view_context.link_to 'Foo', foo_path

Preloaded associations are filtered by conditions on the same table

When you eagerly load an association list using the .include option, and at the same time have a .where on an included table, two things happen:

  1. Rails tries to load all involved records in a huge single query spanning multiple database tables.
  2. The preloaded association list is filtered by the where condition, even though you only wanted to use the where condition to filter the containing model.

The second case's behavior is mostly unexpected, because pre-loaded associations usually don't care about the circumstances under whi...

ActiveRecord: Specifying conditions on an associated table

We can use ActiveRecord's where to add conditions to a relation. But sometimes our condition is not on the model itself, but on an associated model. This card explains multiple ways to express this condition using ActiveRecord's query interface (without writing SQL).

As an example we will use a User that has many Posts:

class User < ApplicationRecord
  has_many :posts
  scope :active, -> { tra...

Generating test images on the fly via JavaScript or Ruby

When you need test images, instead of using services like lorempixel or placehold.it you may generate test images yourself.

Here we build a simple SVG image and wrap it into a data: URI. All browsers support SVG, and you can easily adjust it yourself.
Simply set it as an image's src attribute.

JavaScript

Simple solution in modern JavaScript, e.g. for use in the client's browser:

function svgUri(text) {
  let svg = `
    <svg wid...

Pattern: Disabling a certain feature in tests

There is a kind of features in web applications that hinder automated integration tests. Examples include cookie consent banners or form captchas. Clearly, these should be disabled so you do not have to explicitly deal with them in each and every test (like, every test starting with accepting the cookies notice). On the other hand, they must be tested as well.

A good feature disabling solution should therefore meet these requirements:

  • The feature is generally disabled in tests. A test does not need to do anything manually.

  • It is *...

Ruby: A small summary of what return, break and next means for blocks

Summary

  • Use return to return from a method. return accepts a value that will be the return value of the method call.
  • Use break to quit from a block and from the method that yielded to the block. break accepts a value that supplies the result of the expression it is “breaking” out of.
  • Use next to skip the rest of the current iteration. next accepts an argument that will be the result of that block iteration.

The following method will serve as an example in the details below:

def example
  puts yield
  puts ...

Defining custom RSpec matchers

There are three ways to define your own RSpec matchers, with increasing complexibility and options:

1) Use RSpec::Matchers.define

RSpec::Matchers.define :be_a_multiple_of do |expected|
  match do |actual|
    actual % expected == 0
  end
  
  # optional
  failure_message do |actual|
    "expected that #{actual} would be a multiple of #{expected}"
  end
  
  # optional
  failure_message_when_negated do |actual|
    "expected that #{actual} would not be a multiple of #{expected}"
  end
end
  • This is automatically available i...

Lazy-loading images

Note

This card does not reflect the current state of lazy loading technologies. The native lazy attribute could be used, which is supported by all major browsers since 2022.

Since images are magnitudes larger in file size than text (HTML, CSS, Javascript) is, loading the images of a large web page takes a significant amount of the total load time. When your internet connection is good, this is usually not an issue. However, users with limited bandwidth (i.e. on mobile) need to mine their data budget...

Preconnect, Prefetch, Prerender ...

A very informative and interesting presentation about browsing performance, looking at efforts Google Chrome takes to increase it.

From those slides

There is a bunch of interesting pages in Chrome:

  • chrome://dns - List of prefetched DNS
  • chrome://predictors/ - Chrome knows where you'll go

Preconnect

With <link rel="preconnect" href="https://the-domain.com"> in an HTML head, you give the browser an early hint that it will need to access the mentioned domain. By setting up the connection in advance, page load performance gets im...

RSpec: How to compare ISO 8601 time strings with milliseconds

Rails includes milliseconds in Time / DateTime objects when rendering them as JSON:

JSON.parse(User.last.to_json)['created_at']
#=> "2001-01-01T00:00:00.000+00:00"

In RSpec you might want to use .to_json instead of .iso8601 to use the build-in eq matcher:

it 'returns the created at attribute of a user' do
  get '/users/1'
  
  expect(JSON.parse(response.body)['created_at']).to eq(Time.parse('2001-01-01').to_json)
end

Otherwise the strings do not match:

DateTime.parse('2001-01-01').to_s (will defa...

How to reliably center (block) icons vertically with text

vertical-align is hard. Have you ever wanted to vertically center an icon with text? This usually means "vertically align with capital letters", as visually, a text line goes from baseline up to the capital top. (That's because descenders are far less frequent than ascenders.)

In this card we'll vertically center an icon (or any "blockish" inline element, really) with the capital letters of surrounding text. This works well with our [modern approach to SVG icons](/mak...

How to kill a Rails development server by force

Sometimes, the rails dev server doesn't terminate properly. This can for example happen when the dev server runs in a RubyMine terminal.

When this happens, the old dev server blocks port 3000, so when you try to start a new server, you get the error:

Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)

You can terminate such a dev server with this command:

lsof -t -i :3000 -s TCP:LISTEN | xargs kill -9

It might be worth it to add this to your bash aliases.

Consul 1.3.0 lets you override generated controller methods

When you use the :as option to map a power to a controller method you can now override the generated method. The original implementation can be accessed with super.

This is useful to chain additional conditions to a scope:

class NotesController < ApplicationController

  power :notes, as: :note_scope

  # ...
  
  private
  
  def note_scope
    super.where(trashed: false)
  end

end

Dynamic super-overridable methods in Ruby – The Pug Automatic

How a macro can dynamically define a method that can be overridden with super in the same class.

You can use the with_module_inheritance helper below if you want. It can be handy to make parts of a modularity trait super-able.

# ./lib/ext/module/with_module_inheritance.rb
#
# This macro allows you to define methods in a modularity trait that can be
# modified using the `super` keyword
# See https://thepugautomatic.com/2013/07/dsom/
module WithModuleInheritance
  def with_module_inher...

Fixing wall of net/protocol warnings

After upgrading to Rails 6.1.7.2 one of our apps printed a wall of warnings while booting:

/var/www/app/shared/bundle/ruby/2.6.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:68: warning: already initialized constant Net::ProtocRetryError
/home/deploy-app/.rbenv/versions/2.6.10/lib/ruby/2.6.0/net/protocol.rb:66: warning: previous definition of ProtocRetryError was here
/var/www/app/shared/bundle/ruby/2.6.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:214: warning: already initialized constant Net::BufferedIO::BUFSIZE
/home/deploy-app/.rben...

Why Sidekiq Jobs should never be enqueued in an `after_create` or `after_save` callback

When an object is created / updated, various callbacks are executed in this order:

before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit / after_rollback

Thus, each of these callbacks is executed at a specific time in the life cycle of the object. This is important because this point in time determ...

Defining class methods with Modularity traits

There are two ways to define a class method from a Modularity trait. Note that the usual caveats regarding class method visibility apply.

Using define_method

The recommended way is to define a method on your module's singleton class:

module SomeTrait
  as_trait do
    define_singleton_method :foo do
      # ...
    end
  end
end

Using def (has...

Do not rescue inline in Ruby

When you are calling a method that may raise an exception that you don't care about, you might think of doing something like this:

@user = User.power_find(something) rescue User.new

Do not do that! You will be rescuing away StandardError and all its subclasses, like NameError -- meaning that even a typo in your code won't raise an error.

Instead, rescue the exception type that you are expecting:

@user = begin
  User.power_find(something)...