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
prependhappens beforealias_method - If you can control the
alias_methodinvocation: rewrite to the modern & betterprepend - If you can only control the
prependinvocation: 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.lockinto 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
asdfallows you to manage multiple runtime versions with a single CLI tool and is backwards compatible by supporting existing config files, like e.g..nvmrcor.ruby-version.
Getting Started
- Disable rbenv
1.1 Delete or comment outsource /home/$user/.rbenvrcin~/.profile
1.2 Delete or comment oureval "$(rbenv init -)"in~/.bashrcor~/.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...
How Haml 6 changes attribute rendering, and what to do about it
Haml 6 was a major rewrite with performance in mind. To achieve a performance improvement of 1.7x, some design trade-offs had to be made. The most notable change might be the simplified attribute rendering.
In Haml 5, attribute rendering knew two special cases: an attribute with value true would be rendered without a value, an attribute with a falsy value would not be rendered at all. All other values would just be rendered as attribute values.
According to the Haml maintai...
Using Capybara finder methods with arbitrary matching conditions
Capybara has a variety of finder methods like find_button to help you look up DOM elements. There are also matchers like have_field to make expectations during tests.
These methods also have a number of options to influence the lookup. E.g. the :disabled option lets you control whether Capybara will match disabled fields.
If you have a matching condition that cannot be expressed by the existing Capybara opt...
Rails: Your index actions probably want strict_loading
By activating strict_loading you force developers to address n+1 queries by preloading all associations used in the index view. Using an association that is not preloaded will raise an ActiveRecord::StrictLoadingViolationError.
I think it's a good default to activate strict_loading in your controllers' #index actions. This way, when a change introduces an n+1 query, you...
How to exclusively lock file access in ruby
We will achieve this by creating a block accepting method to optionally create and then lock a .lock File of the underlying accessed file.
Why create a .lock file?
- The main advantage of creating a
.lockfile is that#flockmight block some operations and require the index node of the file to be consistent. Some operations might change that index node. - In some cases it might also be convenient to just read/write the lock file first and update the other file afterwards or vice versa, such that breaking of a process does not...
How to enable template coverage support for simplecov
Since Ruby 3.2.0 you can measure coverage support for eval statements and support has been added for the simplecov gem as well.
This allows to track coverage across ruby templates such as haml, erb, ...
Simply set this within simplecov
SimpleCov.start do
enable_coverage_for_eval
end
Heads up: Deployment with newly generated SSH key (using ED25519) might fail
If you use a newer SSH key generated with the ED25519 algorithm instead of RSA (see Create a new SSH key pair), the deployment with Capistrano may fail with the following message:
The deploy has failed with an error: unsupported key type `ssh-ed25519'
net-ssh requires the following gems for ed25519 support:
* ed25519 (>= 1.2, < 2.0)
* bcrypt_pbkdf (>= 1.0, < 2.0)
See https://github.com/net-ssh/net-ssh/issues/565 for more information
Gem::LoadError : "ed25519 i...
Issue Checklist Template
This is a checklist I use to work on issues. For this purpose I extracted several cards related to the makandra process and ported them into a check list and refined that over time a little bit.
This task list is divided by the Gate keeping process in the following steps:
1. Starting a new feature
2. Working on the issue
3. Finishing a feature
4. After Review
Here are some ti...
Rails: Using database default values for boolean attributes
In the past we validate and set default values for boolean attributes in Rails and not the database itself.
Reasons for this:
- Older Rails didn't support database defaults when creating new records
- Application logic is "hidden" in the database
An alternative approach, which currently reflects more the general opinion of the Rails upstream on constraints in the database, is adding default values in the schema of the database itself. We also ...
HTTP headers can only transport US-ASCII characters safely
HTTP header values must only contain low-ASCII (7-bit) characters for safe transport. From RFC 7230:
Historically, HTTP has allowed field content with text in the ISO-8859-1 charset [ISO-8859-1], supporting other charsets only through use of [RFC2047] encoding. In practice, most HTTP header field values use only a subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD limit their field values to US-ASCII octets.
If you need to transport 8-bit+ characters (e.g...
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 describecommand will return the last tag before a c...
Postgres: DISTINCT ON lets you select only one record per ordered attribute(s) for each group
-
To retrieve only unique combinations of the selected attributes: You can omit rows, where all selected columns are equal with the
DISTINCTstatement. -
To retrieve the group wise maximum of certain columns: You can keep only one record for each group with the
DISTINCT ONstatement, to omit equal rows within each specified group.
Use case
You have a query where you want only one record for a set of specifically ordered attributes.
How to use?
Let's say we look at the example how to query only the latest post for each user:
...
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...
Signed URLs with Ruby on Rails
Using ActiveRecord's #signed_id and .find_signed methods you can create URLs that expire after some time. No conditionals or additional database columns required.