Transfer records to restore database entries (with Marshal)
If you ever need to restore exact records from one database to another, Marshal
might come in handy.
Marshal.dump
is part of the ruby core and available in all ruby versions without the need to install anything. This serializes complete ruby objects including id
, object_id
and all internal state.
Marshal.load
deserializes a string to an object. A deserialized object cannot be saved to database directly as the the dumped object was not marked dirty, thus rails does not see the need to save it, even if the object is not present in...
Ruby: Using `sprintf` to replace a string at fixed named references
The sprintf
method has a reference by name format option:
sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) # => 1 : 2.000000
sprintf("%{foo}f", { :foo => 1 }) # => "1f"
The format identifier %<id>
stands for different data types to be formatted, such as %f
for floats:
sprintf('%f', 1) # => 1.000000
Example:
This is quite useful to replace ...
Using Rationals to avoid rounding errors in calculations
Ruby has the class Rational which allows you to store exact fractions. Any calculation on these variables will now use fractional calculations internally, until you convert the result to another data type or do a calculation which requires an implicit conversion.
Example use case:
Lets say you want to store the conversion factor from MJ
to kWh
in a variable, which is 1/3.6
. Using BigDecimals for this seems like a good idea, it usually helps with rounding errors over a float, but the...
Zeitwerk: How to collapse folders in Rails
All direct child directories of app
are automatically added to the eager- and autoload paths. They do NOT create a module for namespacing. This is intuitive, since there normally is no module Model
, or module Controller
. If you want to add a new base directory, there's no additional config needed.
Example
app
├── controllers
├── helpers
├── inputs # No config needed
├── mailers
├── models
├── uploaders # No config needed
├── util # No config needed
└── workers # No config needed
Sometimes it's handy to group files wit...
Solving "TypeError (nil can't be coerced into Integer)" in the Rails console / IRB
On the Rails console, assigning an object to a variable can lead to this strange error (without stacktrace):
irb > recipient = Recipient.find(123)
Traceback (most recent call last):
TypeError (nil can't be coerced into Integer)
irb > recipient
#<Recipient ...
The error is only in the output – the assignment is working. It only occurs when using the --nomultiline
option, and thus [only with IRB 1.2.0+ and before Ruby 3](https://github.com/makandra/geordi/blob...
Ruby: `extend` extends the singleton class's inheritance chain
In the discussion of the difference between include
and extend
in Ruby, there is a misconception that extend
would add methods to the singleton class of a ruby object as stated in many posts on this topic. But in fact, it is added to the ancestors chain of the singleton class! Even though it is technically not the same, practically this can be considered the same in most use cases.
Example
This means, that we are able to overwrite these methods or call the parent version with super
depending in which order and in whi...
Debug MiniMagick calls in your Rails app
Most of our applications use CarrierWave for file uploads. CarrierWave has an integrated processing mechanism for different file versions with support for ImageMagick through CarrierWave::MiniMagick
(which requires the mini_magick
gem). In case your processing runs into an error, CarrierWave will just swallow it and rethrow an error with a very generic message like Processing failed. Maybe it is not an image?
which does not help you finding out what the actual problem is. CarrierWave probably does this for security purposes, but does n...
Spreewald, Cucumber: Selector for the nth element
The recommended additional setup of the spreewald gem, a useful set of cucumber steps, includes adding a file for defining custom selectors which can be used as prose within steps:
When I follow "Edit" within the controls section
Where the controls section
can be any arbitrary defined css selector within selectors.rb
Often it can be useful to select the nth element of a specific selector. Luckily, this can ...
How to make sure that manual deploy tasks (scheduled in Pivotal Tracker) are executed on deploy (with Capistrano)
We regularly have tasks that need to be performed around a deploy. Be it to notify operations about changed application behavior, be it to run a little oneline script after the deploy. Most database-related stuff can be handled by migrations, but every once in a while, we have tasks that are much easier to be performed manually.
Writing deploy tasks
Here is how we manage the deploy tasks themselves:
- Deploy tasks are written inside the Pivotal Tracker story description, clearly marked (e.g. with a headline "Deploy task")
- We disting...
Using Ruby's Method objects for inspecting methods
Do you remember finding where a method is defined?
I recently learned from a senior colleague that Method objects are quite useful within a debugging feast to find out the currently defined internals of methods, because they are either called within the current context or because you want to learn something about the API of the current objects.
Why is this useful?
This is especially useful since Ru...
Use rbenv-each to run a command for every installed Ruby version
The linked rbenv plugin rbenv-each is very helpful to keep QoL gems up to date that are not part of the Gemfile.
For example, you can bump the geordi
version for all your rubies with the following command:
rbenv each gem update geordi
Another useful example would be to bulk-update bundler
or rubygems.
Note that rbenv-each
hasn't been updated since 2018, but it is fully functiona...
Don't use log level :debug in your production environments
Catch phrase
You don't want sensitive user data in your logs.
Background
Rails per default filters sensitive data like passwords and tokens and writes [FILTERED]
to the logs. The code which is responsible for enabling that usually lives in filter_parameter_logging.rb
(Rails.application.config.filter_parameters
). Here is an example of a filtered log entry:
Unfiltered:
`User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2 [["token", "secret-token"], ["LIMIT", 1]]`
After the filter is appl...
Advanced plotting in Ruby with Gnuplot
Besides Plotting graphs in Ruby with Gruff, which comes handy for many uses cases, you sometimes might need configuration for more advanced plots, e.g. for academic concerns. Then using Gnuplot, the first academic open source plotting software, might be a good option.
There are several wrappers for Ruby available and I mainly looked at one of the two most frequently used ones, which are [ruby_gnuplot](https://github.com/rdp/ruby_gnuplot...
Split your parallel tests by execution time and keep execution logs up to date
Both knapsack
and parallel_tests
have the option to split groups by historic execution time. The required logs for this might be outdated since you manually have to update and push them into your repository.
The following card includes an option how you can keep them consistently up to date with no extra effort locally and/or remotely.
How to always split by execution logs
Parallel Tests
The parallel_tests
gem has the option flag `--group...
Lightning Talk: Coverage based Test Case Prioritization in Ruby on Rails
For my computer science bachelor's thesis I programmed and evaluated a CLI Test Case Prioritization (TCP) tool for makandra. It has been written as a Ruby Gem and was tested and evaluated against one Ruby on Rails project. This card will summarize and present the research results, the evaluation and the programmed CLI tool.
The code has been published for educational purposes on GitHub. The german bachelor's thesis has also been included for download at the end.
...
Do not pass params directly into url_for or URL helpers
Rails' url_for
is useful for generating routes from a Hash, but can lead to an open redirect vulnerability.
Your application's generated route methods with a _url
suffix are also affected because [they use url_for
unter the hood](https://github.com/rails/rails...
CarrierWave: Processing images with libvips
When you write your next CarrierWave uploader, consider processing your images with libvips instead of ImageMagick.
Reasons for libvips
There are several upsides to using libvips over ImageMagick:
- libvips is considerably faster and uses less memory.
- ImageMagick has a large attack surface that has repeatedly caused security incidents in the past (compare [ImageMagick CVEs](https://www....
RubyMine: Fixing "Rubocop returned exit code -1. See the logs for details"
When RubyMine reports Rubocop returning "exit code -1", upgrading Rubocop can be the fix:
gem install rubocop
"The logs" can be accessed with Ctrl + Shift + A > Show log in (Files). This opens your file manager at the IDEA log location; the log file is called "idea.log".
If your operating system supports it, right click into the file manager > Open in Terminal. There run tail -f idea.log
to follow the log.
Ruby: alias_method conflicting with prepend
alias_method
makes a copy of a method. This works fine until the same method is overridden using prepend
. If the prepend
is executed after alias_method
, you'll either see an infinite loop, or loose the prepended functionality.
Solution
Your options are:
- Ensure
prepend
happens beforealias_method
- If you can control the
alias_method
invocation: rewrite to the modern & betterprepend
- If you can only control the
prepend
invocation: rewrite to the legacyalias_method
Best practice: How to manage versions in a Gemfile
It most cases it's not necessary to add a version constraint next to your gems in the Gemfile
. Since all versions are saved in the Gemfile.lock
, everyone running bundle install
will get exactly the same versions.
There are some exceptions, where you can consider adding a version constrain to the Gemfile
:
- You are not checking in the
Gemfile.lock
into the version control (not recommended) - A specific gem has a bug in a more recent version (adding a comment for the reason is highly recommended)
- You want to ensure no one upgrade...
How to pretty print all values in a Redis database
With this Ruby script you can print all values in a Redis database to your console (derived from this bash script).
Note: Do not run this command in production. This is for debugging purposes only.
def pretty_print_redis(redis)
redis.keys.each_with_object({}) do |key, hash|
type = redis.type(key)
hash[key] = case type
when 'string'
redis.get(key)
when 'hash'
redis.hgetall(key)
when 'list'
redis.lrange(key, 0, -1)
when 'set'
redis.smembers(...
ASDF: A Version Manager To Rule Them All
tl;dr
asdf
allows you to manage multiple runtime versions with a single CLI tool and is backwards compatible by supporting existing config files, like e.g..nvmrc
or.ruby-version
.
Getting Started
- Disable rbenv
1.1 Delete or comment outsource /home/$user/.rbenvrc
in~/.profile
1.2 Delete or comment oureval "$(rbenv init -)"
in~/.bashrc
or~/.zshrc
1.3 To take effect you may have to restart your shell or log out and log in again from your current linux session - Install asdf by following the official ...
ActiveRecord::Relation#merge overwrites existing conditions on the same column
In Ruby on Rails ActiveRecord::Relation#merge
overwrites existing conditions on the same column. This may cause the relation to select more records than expected:
authorized_users = User.where(id: [1, 2])
filtered_users = User.where(id: [2, 3])
authorized_users.merge(filtered_users).to_sql
# => SELECT * FROM users WHERE id IN (2, 3)
The merged relation select the users (2, 3)
, although we are only allowed to see (1, 2)
. The merged result should be (2)
.
This card explores various workarounds to combine two scopes so t...
How to create a multiline map in SASS/SCSS
If you want to to create maps within SASS/SCSS-files, it normally works like this:
$some-map: (key1: value1, key2: value2)
However, some maps can get big really fast, if they are being used to contain all of the project's icon names and their sizes for example.
Therefore splitting a map into multiple lines, like we do it in Ruby with big hashes, would become really handy.
Unfortunately SASS doesn't support multiline maps. There has been an open issue since 2011 and it hasn't been...