Capistrano: Configure environment specific array attributes

Using Capistrano, we usually have some array configurations in the config/deploy.rb file, like set :linked_files, %w[config/database.yml], so in this case we don't have to manage the database configuration individually on every server.

In a specific case, one of our projects supports sign in by SAML, but not every deploy target has this feature activated. Here comes a nice handy Capistrano feature, which lets us modify the default configuration for individual env...

Rails I18n scope for humanized attribute names

ActiveModel classes have a class method .human_attribute_name. This returns a human-readable form of the attribute:

Person.human_attribute_name("first_name") # => "First name"

By default Rails will use String#humanize to format the attribute name, e.g. by replacing underscores with spaces and capitalizing the first word. You can configure different translation in your I18n locales, e.g. in config/locales/en.yml:

en:
  activerecord:
    attribute...

Deployment: Merge consecutive commits without cherry-picking

You want to deploy new features but the latest commits are not ready for production? Then use git merge master~n to skip the n-last commits.

Tip

A big advantage of merging vs. cherry-picking is that cherry-picking will create copies of all picked commits. When you eventually do merge the branch after cherry-picking, you will have duplicate commit messages in your history.

Example

It's time for a production deployment!

git log --pretty=format:"%h - %s" --reverse origin/production..origin/master

0e6ab39f - Feature A
6396...

The Framework Field Guide - Fundamentals | Unicorn Utterances

I used two lab days to read the The framework field guide - Fundamentals, the first of a three part series to learn the basics of frontend technologies. I can highly suggest it for learning the fundamentals. 'The framework field guide' is written by Unicron Utterances and there side has many high quality articles on web development and computer science related to programming.

[The Framework Field Guide](https://unicorn-ut...

RSpec: Applying stubs only within a block

When you mocked method calls in RSpec, they are mocked until the end of a spec, or until you explicitly release them.

You can use RSpec::Mocks.with_temporary_scope to have all mocks applied inside a block to be released when the block ends.
Example:

RSpec::Mocks.with_temporary_scope do
  allow(Rails).to receive(:env).and_return('production'.inquiry)
  puts Rails.env # prints "production"
end
puts Rails.env # prints "test"

Note that, when overriding pre-existing mocks inside the block, they are not reverted to the previously ...

Configuring ActionMailer host and protocol for URL generation

When you generate a URL in a mailer view, ActionMailer will raise an error unless you previously configured it which hostname to use.

There are two options to set the default_url_options of ActionMailer:

  1. Hardcoded solution (preferred solution when using Rails with ActiveJob/Sidekiq or Cronjobs)
  2. Dynamic solution

1. Hardcoded solution

When you are sending mails from outside the request cycle, e.g. ActiveJob/Sidekiq or Cronjobs, y...

Modern HTTP Status codes for redirecting

Formerly 301 (Moved Permanently) and 302 (Found) were used for redirecting. Browsers did implement them in different ways, so since HTTP 1.1 there are some new status codes which allow for finer distinctions.

The interesting part is how non-GET requests are handled by the redirect. It is preferrable to use the newer status code to avoid unexpected behavior.

303 See Other

The response to the request can be found under anot...

How to list updateable dependencies with Bundler and Yarn

Bundler

bundle outdated [--filter-major|--filter-minor|--filter-patch]

Example output for bundle outdated --filter-major

Image

Other examples

A useful flag is --strict as it will only list versions that are allowed by your Gemfile requirements (e.g. does not show rails update to 6 if your Gemfile has the line gem 'rails', '~>5.2').

I also experienced that doing upgrades per group (test, development) are easier to do. Thus --groups might also be helpful.

$ bundle...

angular_xss 1.0 released (final release)

A bug report triggered us to

  1. improve support of angular_xss for HAML6 and Rails 7.1
  2. find out that the gem is no longer needed for any of our projects in active development

angular_xss 1.0 is thus the final release, it's now marked as unmaintained

1.0 2024-07-02

Compatible changes

  • Bump version to 1.0 as this gem has been production-ready for 10 years
  • Declare the gem to be unmaintained
  • Add compatibility with Rails 7.1
  • Add compatibility with HAML 6
    • NOTE: Don't use HAML 6.0.0. AngularXSS relies on a patch [introdu...

Updated: CarrierWave: Processing images with libvips

mutate blocks are only required for draw operations, and for writing metadata. You cannot call operations like scale() on mutable images.

Even though most libvips operations return a new, immutable Vips::Image, libvips uses a clever internal representation that avoids the need to allocate memory for every intermediate image. See the How it works section on libvips.org for details.

Updated: Don't name columns like counter_cache columns in Rails pre v4.2.4

Added a link to the commit resolving the issue and included the affected rails versions.

Caveat when using Rails' new "strict locals" feature

In Rails 7.1 it has become possible to annotate partials with the locals they expect:

# partial _user_name.erb
<%# locals: (user:) %>
<%= user.name %>

# view
<%= render 'user_name' %> <%# this raises an ArgumentError %>

Unfortunately, when some other code in that template raises an ArgumentError (for example an error in the User#name method) you will end up with a confusing stacktrace that looks like you have an error in your render call.

If th...

How to tell ActiveRecord how to preload associations (either JOINs or separate queries)

Remember why preloading associations "randomly" uses joined tables or multiple queries?

If you don't like the cleverness of this behavior, you can explicitely tell ActiveRecord how to preload associations with either JOINs or separate queries.

This card gives an overview of the different options to preload associations, but

__Whic...

Async control flow in JavaScript: Promises, Microtasks, async/await

Slides for Henning's talk on Sep 21st 2017.


Understanding sync vs. async control flow

Talking to synchronous (or "blocking") API

print('script start')
html = get('/foo')
print(html)
print('script end')

Script outputs 'script start', (long delay), '<html>...</html>', 'script end'.

Talking to asynchronous (or "evented") API

print('script start')
get('foo', done: function(html) {
  print(html)
})
print('script end')

Script outputs 'script start', 'script end', (long ...

Authorize allowed values with assignable_values

All our projects have enum-like requirements like this:

  • An attribute value must be included in a given set of values.
  • The list of allowed values must be retrievable in order to render <select> boxes.
  • Each value has a humanized label.
  • Sometimes there is a default value.

Most of the time, this requirement is also needed:

  • The list of assignable values depends on the user who is currently signed in.

In our past projects there are many different solutions for these related requirements, e.g. ChoiceTrait, methods like `available_...

rails_state_machine 3.0.0 released

We released a new version of our rails_state_machine gem. The release contains mainly a breaking change on how errors in state transitions are handled.

Please have a look at the changelog for more details and an upgrade guide:


3.0.0 2024-06-21

Breaking changes

  • Changed: Setting the <state_name>_event to an invalid event adds an error to the attribute instead of raising a `Transitio...

Updated: Breaking changes for boolean attributes in HAML 6

Starting with Unpoly 3.8, most Unpoly attributes can now be enabled with a value "true" and be disabled with a value "false". This pairs well with the default (unpatched) Haml 6 behavior.

capybara-lockstep 2.2.2 released

The capybara-lockstep gem synchronizes Capybara commands with client-side JavaScript and AJAX requests. This greatly improves the stability of an end-to-end ("E2E") test suite, even if that suite has timing issues.

Changes in 2.2.2

  • We now only wait for <script> elements with a JavaScript type
  • We only wait for <iframe> elements with a [src] attribute
  • We no longer wait for <video> and <audio> elements to load their metadata. This did not work consistently, and would sometime...

capybara-lockstep 2.2.1 fixes drivers with { browser: :remote }

Capybara-lockstep < 2.2.1 has a bug that makes it essentially not work when using browser: :remote in your Capybara driver. Please update to 2.2.1 to get the expected functionality.

The affected setups look like this:

chromedriver_url = ENV['CHROMEDRIVER_URL']

Capybara::Selenium::Driver.new(app,
  browser: chromedriver_url ? :remote : :chrome,
  options:,
  **(chromedriver_url ? { url: chromedriver_url } : {}),
)

Note that older Capybara versions used browser: :chrome, url: chromedriver_url, will work fine.

Searchkick: async reindexing fails for rails 7 with redis 4

After an upgrade to rails 7 I noticed that async reindexing jobs of Searchkick were failing for Model.reindex(mode: :async, wait: true):

/home/a_user/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/searchkick-5.3.1/lib/searchkick/relation_indexer.rb:142:in `block in batch_job': undefined method `call' for nil (NoMethodError)

    Searchkick.with_redis { |r| r.call("SADD", batches_key, [batch_id]) }
                                 ^^^^^
from /home/a_user/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/searchkick-5.3.1/lib/searchkick.r...

Why two Ruby Time objects are not equal, although they appear to be

So you are comparing two Time objects in an RSpec example, and they are not equal, although they look equal:

expected: Tue May 01 21:59:59 UTC 2007,
     got: Tue May 01 21:59:59 UTC 2007 (using ==)

The reason for this is that Time actually tracks fractions of a second, although #to_s doesn't say so and even though you probably only care about seconds. This means that two consecutive calls of Time.now probably return two inequal values.

Consider freezing time in your tests so it is not dependent on the speed of the executi...

Don't name columns like counter_cache columns in Rails pre v4.2.4

< Rails v4.2.4

ActiveRecord has a feature called counter caching where the containing record in a has_many relationship caches the number of its children. E.g. when you have House has_many :rooms, Rails can cache the number of rooms in House#rooms_count.

Mind that when a model has a column that looks to Rails like a counter-cache column, Rails will apply counter-cache logic to your model, even if you're not using counter caches.

E.g. you have a house with 12...

Ruby: You can nest regular expressions

Ruby lets you re-use existing RegExp objects by interpolating it into new patterns:

locales_pattern = /de|en|fr|es/i

html_tag_pattern = /<html lang="#{locales_pattern}">/

Any modifiers like /i or /x will be preserved within the interpolated region, which is pretty cool. So in the example above only the interpolated locales are case-insensitive, while the pattern around it (/<html .../) remains case-sensitive.

routing-filter is broken with Rails 7.1

If you are using the routing-filter gem in your Rails 7.1 app for managing URL segments for locales or suffixes, you will notice that the filters do no longer apply, routes are broken and the necessary parameters are no longer extracted. That is because routing-filter patches Rails' find_routes-method to get the current path and apply its defined filters on it. These filters then modify the params that are handed over to your controller action. This way you receive a locale parameter from a ...