Rails: Validations of Dates, Numerics and Strings with ComparisonValidator

tl;dr

Since Rails 7+ you can use ComparisonValidator for validations like greater_than, less_than, etc. on dates, numerics or strings.

Example

We have a model for booking a trip. This model has mandatory attributes to enforce dates for the start and the end.

# == Schema Information
#
# start_date :date
# end_date   :date
# ...

class TripBooking < ApplicationRecord
  validates :start_date, presence: true
  validates :end_date, presence: true
end

These validations are enough. We also want to ensure, th...

How to emulate simple classes with plain JavaScript

If you want a class-like construct in JavaScript, you can use the module pattern below. The module pattern gives you basic class concepts like a constructor, private state, public methods.

Since the module pattern only uses basic JavaScript, your code will run in any browser. You don't need CoffeeScript or an ES6 transpiler like Babel.

A cosmetic benefit is that the module pattern works without the use of this or prototypes.

Example

Here is an example for a Ruby class that we want to translate into Javascript using the module patter...

Whitelist Carrierwave attributes correctly

Say you have a User with a Carrierwave attribute #avatar:

class User < ActiveRecord::Base
  mount_uploader :avatar, AvatarUploader
end

When whitelisting the avatar field in the controller, you might do this:

params[:user].permit(:avatar)

But you probably want this:

params[:user].permit(:avatar, :avatar_cache, :remove_avatar)

In this example:

  • :avatar_cache allows a newly upload image to persist through form roundtrips in the case of validation errors (something that isn't possibl...

Git: Switch

tl;dr

git checkout is the swiss army of git commands. If you prefer a semantically more meaningful command for branch related tasks, use git switch instead.

You can use git switch since git 2.23.

Switch Branch

git branch
# * master
#   feature-branch

git switch feature-branch
git branch
#   master
# * feature-branch

git switch -
git branch
# * master
#   feature-branch

Info

For this use case you can of course also use git checkout.

Switch on a Remote Branch

git branch -a
# * m...

Exploring the disk usage with ncdu

Ncdu is a disk usage analyzer with an ncurses interface. It is designed to find space hogs on a remote server where you don’t have an entire graphical setup available, but it is a useful tool even on regular desktop systems. Ncdu aims to be fast, simple and easy to use, and should be able to run in any minimal POSIX-like environment with ncurses installed.

Image

Alternatives

How to find out what is running on a port on a remote machine

By convention, common protocols use a defined port, like 80 for HTTP or 443 for HTTPS.

You can use nmap to find out what service is running behind a given port, and most often see some details about it. This can be helpful if servers don't offer the services you expect for some ports. If you'd like to see what ports are listing on your local machine, you might want to use netstat instead of nmap.

Note that nmap's service discovery may trigger several requests.

Example

When using nmap, adding the -A switch ...

Organize large I18n dictionary files in Ruby on Rails

If you're suffering from a huge de.yml or similiar file, cry no more. Rails lets you freely organize your dictionary files in config/locales.

My organization works like this:

  • config/locales/rails.de.yml modified Rails boilerplate
  • config/locales/faker.de.yml modified Faker boilerplate
  • config/locales/models.de.yml model names, attribute names, assignable_value labels
  • `config/locales/views.de.y...

ActiveRecord: Named bindings in conditions

In Active Record you can use named bindings in where-conditions. This helps you to make your code more readable and reduces repetitions in the binding list.

Example without named bindings

User.where(
  'name = ? OR email ?',
  params[:query],
  params[:query]
)

Example with named bindings

User.where(
  'name = :query OR email :query',
  query: params[:query]
)

Careful when using Time objects for generating ETags

You can use ETags to allow clients to use cached responses, if your application would send the same contents as before.

Besides what "actually" defines your response's contents, your application probably also considers "global" conditions, like which user is signed in:

class ApplicationController < ActionController::Base

  etag { current_user&.id }
  etag { current_user&.updated_at }

end

Under the hood, Rails generates an ETag header value like W/"f14ce3710a2a3187802cadc7e0c8ea99". In doing so, all objects from that etagge...

Use capybara and not rspec matchers

One rule of thumb I try to follow in capybara tests is using capybara matchers and not plain rspec matchers.

One example:

visit(some_page)
text_field = find('.textfield')
expect(text_field['value']).to match /pattern/

This can work, but is too brittle and flaky. match will not retry or synchronize the value of text_field.

The equivalent code with a capybara matcher:

visit(some_page)
expect(page).to have_field('.textfield', with: /pattern/)

have_field will retry for and synchronize the text_field.

Git: Restore

tl;dr

git checkout is the swiss army of git commands. If you prefer a semantically more meaningful command for restoring tasks, use git restore instead.

With this command you can ...

  • ... do unstaging - git restore --staged
  • ... discard staged changes - git restore --staged --worktree
  • ... discard unstaged changes - git restore
  • ... restore deleted files - git restore
  • ... restore historic versions - git restore --source
  • ... recreate merge conflicts - git restore --merge
  • ... specifiy...

Checklist: Using Carrierwave in a Rails project

This checklist should help you to check edge cases that are not part of the default Carrierwave configuration.

You can implement basic object-fit behavior with background images

So you want to use object-fit, but you also need to support Internet Explorer.

One option is to use lazysizes as a kinda-polyfill. Another option is to implement the requirement with background-size: contain, and background-size: cover, which is supported in IE9+.

E.g. to make an image cover a 100x100 px² area, cropping the image when nece...

How to use pessimistic row locks with ActiveRecord

When requests arrive at the application servers simultaneously, weird things can happen. Sometimes, this can also happen if a user double-clicks on a button, for example.

This often leads to problems, as two object instances are modified in parallel maybe by different code and one of the requests writes the results to the database.

In case you want to make sure that only one of the requests "wins", i.e. one of the requests is fully executed and completed while the other one at least has to wait for the first request to be completed, you ha...

Detect the current Rails environment from JavaScript or CSS

Detecting if a Javascript is running under Selenium WebDriver is super-painful. It's much easier to detect the current Rails environment instead.

You might be better of checking against the name of the current Rails environment. To do this, store the environment name in a data-environment of your <html>. E.g., in your application layout:

<html data-environment=<%= Rails.env %>>

Now you can say in a pi...

In MySQL, a zero number equals any string

In MySQL comparing zero to a string 0 = "any string" is always true!

So when you want to compare a string with a value of an integer column, you have to cast your integer value into a string like follows:

SELECT * from posts WHERE CAST(posts.comments_count AS CHAR) = '200' 

Of course this is usually not what you want to use for selecting your data as this might cause some expensive database operations. No indexes can be used and a full table scan will always be triggered.

If possible, cast the compared value in your application to...

A community-curated list of flexbox issues and cross-browser workarounds for them

This repository is a community-curated list of flexbox issues and cross-browser workarounds for them. The goal is that if you're building a website using flexbox and something isn't working as you'd expect, you can find the solution here.

As the spec continues to evolve and vendors nail down their implementations, this repo will be updated with newly discovered issues and remove old issues as they're fixed or become obsolete. If you discover a bug that's not listed here, please report it so everyone else can benefit.

How to fix "Exit with code 1 due to network error: ProtocolUnknownError" with wkhtmltopdf

New versions of wkhtmltopdf dissallow file:// URLs by default. You can allow them by passing --enable-local-file-access.

If you are using PDFKit, set the option

PDFKit.configure do |config|
  config.default_options = {
    enable_local_file_access: true,
  }
end

This will be necessary in many setups to allow wkhtmltopdf to fetch assets (such as stylesheets) from the filesystem.

Note on security

Allowing this poses some risk when you render user input, since it might be feasible to include data from the local filesyste...

Git commands to discard local changes

Use case

You have uncommited changes (you can always check by using git status), which you want to discard.

Context

Now there are several options to discard these depending on your exact situation.
The headlines will differentiate the cases whether the files are staged or unstaged.

  1. Staged and unstaged changes
  2. [Staged changes](https://makandracards.com/makandra/516559-git-commands-to-discard-local-changes#s...

RubyMine: Find and Replace with Regex (Capture Groups and Backreferences)

tl;dr

In RubyMine you can use find and replace with capture groups (.*?) and backreferences $1 (if you have several groups: $[Capture-Group ID]).
Named captures (?<text>.*) are also supported.

Examples

Replace double quotes with single quotes

If you want to replace double quotes with single quotes, replacing every " with a ' is prone to errors. Regular expressions can help you out here.

  1. Open find and replace
  2. Activate the regex mode (click on the .* icon next to the "find" field).
  3. Fill in f...

SEO: The subtle differences of robots.txt disallow vs meta robots no-index

The robots.txt file and <meta name="robots"> HTML tag can be used to control the behavior of search engine crawlers. Both have different effects.

robots.txt

Marking a URL path as "disallowed" in robots.txt tells crawlers to not access that path.

robots.txt is not a guarantee for exclusion from search engine results.

A "disallowed" URL might be known from an external link, and can still be displayed for a matching search.
Example: even if /admin is disallowed in robots.txt, `/admin/som...

Do not use "flex: 1" or "flex-basis: 0" inside "flex-direction: column" when you need to support IE11

Flexbox is awesome. Most of it even works in IE11, but flex: 1 won't work reliably in Internet Explorer.
This it because implicitly sets flex-basis: 0 which IE fails to support properly.

Example

Consider the following HTML and CSS.

<div class="container">
  <div class="child">
    foo
  </div>
  <div class="bar">
    bar
  </div>
</div>
.container {
  display: flex;
  flex-direction: column;
}

.child {
  flex: 1;
}

See it in action at Plunker.

Background

...

Rails: Overwriting default accessors

All columns of a model's database table are automagically available through accessors on the Active Record object.

When you need to specialize this behavior, you may override the default accessors (using the same name as the attribute) and simply call the original implementation with a modified value. Example:

class Poet < ApplicationRecord

  def name=(value)
    super(value.strip)
  end

end

Note that you can also avoid the original setter and directly read/write from/to the instance's attribute storage. However this is dis...

Project management best practices: Standup

If the project team consists of at least 2 members, do a daily standup. It should not take much longer than 15 minutes.

Format

Tell everyone else

  • what you did yesterday
  • what you intend to do today
  • where you might need help or other input
  • if there are new developments everyone needs to know about

A "still working on X, will probably be done today" is totally fine. No need to tell a long story.

If you are out of work, find a new story with the others.

If there are new stories in the backlog, look at them and

  • make sure ev...