Five years of "Today I Learned" from Josh Branchaud
The linked GitHub repository is a bit like our "dev" cards deck, but groomed from a single person (Josh Branchaud). It includes an extensive list of over 900 TILs on many topics that might be interesting for most of us. (e.g. Ruby, Rails, Git, Unix..)
Ruby
Here is an excerpt of all the Ruby TILs that were new to me. I encourage you to take your time to skim over the original list as well!
-
Assoc For Hashes
- `Hash#ass...
Rails: Concurrent requests in development and tests
With puma
you can have concurrent requests. There are two concepts on how Puma can handle two incoming requests: Workers and Threads.
Workers
Puma can have multiple workers. Each worker is a process fork from puma and therefore a very heavy instance and can have multiple threads, that handle the incoming requests.
Example: A Puma server with 2 workers
and 1 thread
each can handle 2 request in parallel
. A third request has to wait until the thread of one of the workers is free.
Threads
Rails is thread-safe since version 4 (n...
How to use Simplecov to find untested code in a Rails project with RSpec and Cucumber
Simplecov is a code coverage tool. This helps you to find out which parts of your application are not tested.
Integrating this in a rails project with rspec, cucumber and parallel_tests is easy.
-
Add it to your Gemfile and bundle
group :test do gem 'simplecov', require: false end
-
Add a
.simplecov
file in your project root:SimpleCov.start 'rails' do # any custom configs like groups and filters can be here at a central place enable_cov...
Bundler in deploy mode shares gems between patch-level Ruby versions
A recent patch level Ruby update caused troubles to some of us as applications started to complain about incompatible gem versions. I'll try to explain how the faulty state most likely is achieved and how to fix it.
Theory
When you deploy a new Ruby version with capistrano-opscomplete, it will take care of a few things:
- The new Ruby version is installed
- The Bundler version stated in the Gemfil...
Video transcoding: Web and native playback overview (April 2020)
Intro
Embedding videos on a website is very easy, add a <video>
tag to your source code and it just works. Most of the time.
The thing is: Both the operating system and Browser of your client must support the container and codecs of your video. To ensure playback on every device, you have to transcode your videos to one or more versions of which they are supported by every device out there.
In this card, I'll explore the available audio and video standards we have right now. The goal is to built a pipeline that...
Rails: Rest API post-mortem analysis
This is a personal post-mortem analysis of a project that was mainly build to provide a REST API to mobile clients.
For the API backend we used the following components:
- Active Model Serializer (AMS) to serializer our Active Record models to JSON.
- JSON Schema to test the responses of our server.
- SwaggerUI to document the API.
It worked
The concept worked really good. Here are two points that were extraordinary compared to normal Rails project with many UI components:
- Having a Rails application, that has no UI components (only...
How to: Validate dynamic attributes / JSON in ActiveRecord
PostgreSQL and ActiveRecord have a good support for storing dynamic attributes (hashes) in columns of type JSONB
. But sometimes you are missing some kind of validation or lookup possibility (with plain attributes you can use Active Record's built-in validations and have your schema.rb
).
One approach about being more strict with dynamic attributes is to use JSON Schema validations. Here is an example, where a project has the dynamic attributes analytic_stats
, that we can use to store analytics from an external measurement tool.
- A g...
Structuring Rails applications: the Modular Monorepo Monolith
Root Insurance runs their application as a monolithic Rails application – but they've modularized it inside its repository. Here is their approach in summary:
Strategy
- Keep all code in a single repository (monorepo)
- Have a Rails Engine for each logical component instead of writing a single big Rails Application
- Build database-independent components as gems
- Thus: gems/ and engines/ directories instead of app/
- Define a dependency graph of components. It should have few edges.
- Gems and Engines can be extracted easier once nece...
Capybara 'fill_in': Ambiguous match for different input names
When you have two inputs, where one contains the name of the other (eg. Name
and Name with special treatment
), Capybara's fill_in
method will fail with the following message:
Ambiguous match, found 2 elements matching visible field "Name" that is not disabled (Capybara::Ambiguous)
You can force Capybara to match exactly what you are typing (which makes your tests better anyways) with match: :prefer_exact
:
name = 'Name'
value = 'Bettertest Cucumberbatch'
fill_in(field, with: value, match: :prefer_exact)
Furthermore...
A Migration Path to Bundler 2+
Bundler 2 introduced various incompatibilites und confusing behavior. To add to the confusion, Bundler's behavior changed after the release of their version 2.
The linked article explains what happened.
How to update the bundler version in a Gemfile.lock
-
Install the latest
bundler
version:gem install bundler Fetching bundler-2.3.5.gem Successfully installed bundler-2.3.5 1 gem installed
-
Update the bundler version in
Gemfile.lock
:bundle update --bundler
-
Confirm it worked:
$ tail -n2 Gemfile.lock BUNDLED WITH 2.3.5
Notes:
-
Bundler should automatically detect the latest installed version. If it does not, you can specify your preferred version like so:
b...
Bundler: How to release a gem with 2FA enabled
Rubygems supports a 2FA for your account. Once enabled you need to provide your personal OTP code for every release. Despite the CLI of the rake release
task does not work well with the command prompt for your OTP code with Bundler versions < 2.0.2
. It just looks like the task is frozen:
- Workaround 1: Just type your OTP code and hit enter, your gem is released afterwards.
- Workaround 2: Upgrade to Bundler >=
2.0.2.
. Your supported Ruby versions for this gem must be>= 2.3
.
When r...
ActiveSupport includes Timecop-like helpers
ActiveSupport (since 4.1) includes test helpers to manipulate time, just like the Timecop gem:
-
To freeze the current time, use
freeze_time
(ActiveSupport 5.2+):freeze_time
-
To travel to a specific moment in time, use
travel_to
:travel_to 1.hour.from_now
Important
When freezing time with
#travel_to
, time will be frozen (like withfreeze_time
). This means that your application can't detect passage of time by usingTime.now
. -
To travel a re...
Ruby: The YAML safe_load method hides some pitfalls
The Ruby standard lib ships with a YAML Parser called Psych. But serializing and deserializing data seems not as obvious as if you are using JSON.
To safely write and read YAML files you should use Psych#dump
(String#to_yaml
) and Psych.safe_load
(YAML.safe_load
):
data = {'key' => 'value'}.to_yaml
=> "---\nkey: value\n"
YAML.safe_load(data)
=> {"key"=>"value"}
Unfortunately you might encounter a few pitfalls which are not obvious in the first place. All of them are a side effect that you can not configure Psych#dump
to o...
Integrating or upgrading makandra-rubocop
Introduction
Most of the time it is a tedious task to apply a code style guide to an existing code base as there are likely to be a lot of conflicts. At makandra we are using makandra-rubocop to have code style checks. Here is some advice on how to add makandra-rubocop efficiently.
Note
RubyMine by default has a Rubocop inspection with rules that we don't always agree with. We recommend replacing this with makandra-rubocop or disabling the inspection.
...
Fix error: rails console No such file to load -- irb/encoding_aliases.rb (LoadError)
I got this error after upgrading Ruby from 2.4.5 to 2.6.4 when I opened the Rails console - rails server
still worked.
Running via Spring preloader in process 14679
Loading development environment (Rails 5.2.2.1)
Traceback (most recent call last):
.../lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:175:in 'fork': No such file to load -- irb/encoding_aliases.rb (LoadError)
.../lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:175:in 'fork': undefined method 'reject!' for nil:NilClass (NoMethodError)
.../li...
How to enable Chromedriver logging
When using Chrome for Selenium tests, the chromedriver
binary will be used to control Chrome. To debug problems that stem from Selenium's Chrome and/or Chromedriver, you might want to enable logging for the chromedriver itself. Here is how.
Option 1: Use Selenium::WebDriver::Service
In your test setup, you may already have something like Capybara::Selenium::Driver.new(@app, browser: :chrome, options: ...)
, especially when passing options like device emulation.
Similar to options
, simply add an extra key service
and pass an inst...
palkan/isolator: Detect non-atomic interactions within DB transactions
With this gem your transaction
blocks raise an error when they have side effects that cannot be rolled back.
By default it checks whether you're connecting with HTTP, queuing a Sidekiq job or sending an e-mail within a transaction
. You can add custom checks, too.
Found in this RubyGuides article.
Convert SCSS to SASS
The ruby sass gem also installs a command line tool to convert to and from SCSS. Use it for a directory of .scss
-files like
sass-convert -R assets/stylesheets --from scss --to sass
Rails: Do not load frameworks you don't need
Rails is split into a large number of (sub-) frameworks.
The most important and central of those are
- activesupport (extends the Ruby standard library)
- activerecord / activemodel (ORM for Rails)
- actionview / actionpack (controller / views)
- actionmailer (sends mails)
However, there are also some more situational frameworks included, such as
- actioncable (real time communications using websockets)
- actionmailbox (receives mails)
- actiontext (support for WYSIWYG text editor)
- activejob (background jobs)
- activestorage (file uplo...
Take care of existing users when upgrading Clearance
When upgrading Clearance, pay attention whether the password hashing strategy might have changed. Old clearance versions (< 1.0) used SHA1-encrypted passwords by default. Current versions default to BCrypt.
If you simply upgrade without taking this into account, users will get a BCrypt::Errors::InvalidHash
when trying to sign in. Your tests will not notice this, since they create new users for each scenario.
To fix it, you'll either have to force all users to reset their passwords, or you can allow old users to keep signing in with t...
Webpack(er): A primer
webpack is a very powerful asset bundler written in node.js to bundle (ES6) JavaScript modules, stylesheets, images, and other assets for consumption in browsers.
Webpacker is a wrapper around webpack that handles integration with Rails.
This is a short introduction.
Installation
If you haven't already, you need to install node.js and Yarn.
Then, put
gem 'webpacker', '~> 4.x' # check if 4.x is still cu...
Installing Ruby 2.3 or below on Ubuntu 17 and above
From Ubuntu 17, rbenv fails to install Ruby below 2.4 because of a mismatching OpenSSL dependency: it needs libssl1.0-dev
for the installation process, but recent Ubuntus come with libssl-dev
.
From the linked StackOverflow comment:
As far as I know (and tested), Ruby versions < 2.4 requires libssl1.0, while >2.4 libssl1.1+. The two libssl packages conflict with each other, so you can't have both of them, so I had to juggle the libs in order to install the required ruby version. To make things even funnier (or more complicated),...
RubyMine: Efficiently filtering results in the "Finder" overlay
RubyMine comes with a nice way to grep through your project's files: The finder (ctrl + shift + f
). Don't be discouraged about the notice 100+ matches in n+ files
if your searched keyword is too general or widely used in your project.
RubyMine comes with a few ways to narrow down the resulting list, don't hesitate to apply those filters to speed up your search. Your keybinding might vary based on your personal settings.
File mask (alt + k
)
If you already know the file extension of your ...