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.
- Open find and replace
- Activate the regex mode (click on the
.*icon next to the "find" field). - Fill in f...
Heads up: network requests `Kernel#open` are not mocked with VCR
We usually rely on VCR and WebMock to prevent any real network connection when running our unit tests.
This is not entirely true: They are both limited to a set of HTTP libraries listed below (as of 2022). Direct calls to Kernel#open or OpenURI#open_uri are not mocked and will trigger real network requests even in tests. This might bite you e.g. in [older versions of CarrierWave](https://github.com/carrierwaveuploader/carrierwave/blob/0.11-stable/lib/carrierwave/upl...
Using the ActiveSupport::BroadcastLogger
The ActiveSupport::BroadcastLogger allows you to log to multiple sinks. You know this behavior from from the rails server command, that both logs to standard out and the log/development.log file.
Here is an example from the ActiveSupport::BroadcastLogger API:
stdout_logger = ActiveSupport::Logger.new(STDOUT)
file_logger = ActiveSupport::Logger.new("development.log")
broadcast = ActiveSupport::BroadcastLogger.new(stdout_logger, file_logger)
broadcast.i...
Jasmine: Dealing with Randomness
Whenever you have to deal with randomness in a jasmine test there are some spy strategies to help you out!
Let's say we have a method Random.shuffle(array) to shuffle an array randomly and a class that uses shuffle within the constructor.
returnValue & returnValues
it('shuffles the array', () => {
spyOn(Random, 'shuffle').and.returnValue([3, 2, 1])
array = [1, 2, 3]
testedClass = new testedClass(array)
expect(Random.shuffle).toHaveBeenCalled()
expect(testedClass.array).toEqual([3, 2, 1])
})
If you have...
A simple example with a GIN index in Rails for optimizing a ILIKE query
You can improve your LIKE / ILIKE search queries in PostgreSQL by adding a GIN index with an operate class ("opclass") to split the words into trigrams to the required columns.
Example
class AddSearchTextIndexToUsers < ActiveRecord::Migration[7.1]
def change
enable_extension 'pg_trgm'
add_index :users, :search_tex...
How to: Use git bisect to find bugs and regressions
Git allows you to do a binary search across commits to hunt down the commit that introduced a bug.
Given you are currently on your branch's HEAD that is not working as expected, an example workflow could be:
git bisect start # Start bisecting
git bisect bad # Tag the revision you are currently on (HEAD) as bad. You could also pass a commit's SHA1 like below:
git bisect good abcdef12345678 # Give the SHA1 of any commit that was working as it should
# shorthand:
git bisect start <bad ref> <good ref>
Git will fetch a comm...
Enumerators in Ruby
Starting with Ruby 1.9, most #each methods can be called without a block, and will return an enumerator. This is what allows you to do things like
['foo', 'bar', 'baz'].each.with_index.collect { |name, index| name * index }
# -> ["", "bar", "bazbaz"]
If you write your own each method, it is useful to follow the same practice, i.e. write a method that
- calls a given block for all entries
- returns an enumerator, if no block is given
How to write a canonical each method
To write a m...
PostgreSQL: Be careful when creating records with specific ids
In tests, it is sometimes useful to create records with specific ids. On PostgreSQL this can cause problems:
Usually, PostgreSQL uses an "autoincrement" sequences to provide sequential ids for new database rows. However, these sequences will not increment if you insert a record "by hand". This will cause an error:
record = Record.create!
record.id # => 100, next automatic id will be 101
Record.create!(id: record.id + 1) # okay, but next automatic id will still be 101
Record.create! ...
Spreewald development steps
Our gem spreewald supports a few helpers for development. In case you notice errors in your Cucumber tests, you might want to use one of them to better understand the underlying background of the failure. The following content is also part of the spreewald's README, but is duplicated to this card to allow repeating.
Then console
Pauses test execution and opens an IRB shell with current cont...
Unpoly: Showing the better_errors page when Rails raises an error
When an AJAX request raises an exception on the server, Rails will show a minimal error page with only basic information. Because all Unpoly updates work using AJAX requests, you won't get the more detailled better_errors page with the interactive REPL.
Below is an event listener that automatically repeats the request as a full-page load if your development error shows an error page. This means you get...
Rails: Using custom config files with the config_for method
You can use the config.x configuration in combination with config_for to configure global settings for your Rails 4.2+ application.
Example
In your config/application.rb assign the settings from e.g. config/settings.yml as follows:
module FooApplication
class Application < Rails::Application
config.x.settings = config_for(:settings)
end
end
The config/settings.yml might look as follows:
shared: &shared
email: info@example.com
...
Always convert and strip user-provided images to sRGB
Debugging image color profiles is hard. You can't trust your eyes in this matter, as the image rendering depends on multiple factors. At least the operation system, browser or image viewer software and monitor influence the resulting image colors on your screen.
When we offer our users the possibility to upload images, they will most likely contain tons of EXIF metadata and sometimes exotic color profiles like eciRGB. We want to get rid of the metadata, as it might contain sensitiv...
Open UI: Future development in web components and controls
tl;dr When browsers start to adapt proposals from Open UI, it might not be necessary to use any 3rd party libraries to have nice components and controls in web applications e.g. selects. It would require only a minimum of CSS and Javascript to get them working and looking good.
The purpose of the Open UI, a W3C Community Group, is to allow web developers to style and extend built-in web UI components and controls, such as
<select>dropdowns, checkboxes, radio buttons, and date/color pickers.To do that, we’ll need to fully speci...
Selenium: Fix Chrome's "Unsafe Password" Warning
tl;dr
Set
profile.password_manager_leak_detectiontofalsein your Selenium Chrome options to disable password leak detection and suppress the warning.
Problem
When running Selenium tests with recent versions of Chrome and Chromedriver (e.g., version 136+), entering “unsafe” (weak or reused) passwords in forms triggers a browser warning:
"This password has appeared in a data breach…"
This alert can break automated test runs, especially in CI/CD pipelines.
Solution
You can **disable Chrome’s password leak ...
Rules of thumb against flaky specs
Here are a few common patterns that will probably lead to flaky specs. If you notice them in your specs, please make sure that you have not introduced a flaky spec.
Using 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 equivale...
Error handling in DOM event listeners
When an event listener on a DOM element throws an error, that error will be silenced and not interrupt your program.
In particular, other event listeners will still be called even after a previous listener threw an error. Also the function that emitted the event (like element.dispatchEvent() or up.emit()) will not throw either.
In the following example two handlers are listening to the foo event. The first handler crashes, th...
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 ...
Ruby: How to make your ruby library configurable
You might know a few examples, where you configure some library via a block. One example is the Rails configuration:
Rails.application.configure do |config|
config.enable_reloading = false
end
This card describes a simple example on how to make your ruby library configurable.
Example
module FooClient
class Client
class_attribute :config
def self.configure
self.config ||= Configuration.new
yield(config)
end
def test
uri = URI.parse(FooClient::Client.config.endpoint)
Net:...
How to fix parallel_tests with Redis on powerful machines
When you have a powerful machine with many CPU cores, you might run into an error like
ERR DB index is out of range (Redis::CommandError)
This is because Redis defaults to at most 16 databases (0 to 15) and running tests in parallel might exceed that (your tests might run on databases 1..n or 2..(n+1)).
You can increase that limit:
-
Get number of CPUs of your machine.
nproc --all -
Open up Redis configuration file.
sudo vim /etc/redis/redis.conf -
Find
databasesrow and increase it, e.g. set to 32:
...
Adding Jasmine JavaScript specs to a Webpack(er) project
The goal is to get Jasmine specs running in a Rails project using Webpacker, with the browser based test runner. Should be easily adaptable to a pure Webpack setup.
Step 1: Install Jasmine
yarn add jasmine-core
Step 2: Add two separate packs
Since we do not want to mix Jasmine into our regular Javascript, we will create two additional packs. The first only contains Jasmine and the test runner. The second will contain our normal application code and the specs themselves.
We cannot...
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:
- Hardcoded solution (preferred solution when using Rails with ActiveJob/Sidekiq or Cronjobs)
- Dynamic solution
1. Hardcoded solution
When you are sending mails from outside the request cycle, e.g. ActiveJob/Sidekiq or Cronjobs, y...
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...
Do not forget mailer previews
When changing code in mailers, updating the corresponding mailer preview can be forgotten very easily.
Mailer previews can be tested like other code as well and I sometimes add the following tests to test suites:
# Make sure to require the previews
Dir[Rails.root.join('spec/mailers/previews/*.rb')].each { |file| require(file) }
ActionMailer::Preview.all.index_with(&:emails).each do |preview, mails|
mails.each do |mail|
describe preview do
specify "##{mail} works" do
expect { preview.call(mail...
RSpec: Scoping custom matchers to example groups
When you find yourself in the situation that you would like to define a custom matcher in your specs, but you do not want to define a global matcher since you need it only for your specific test, there are two ways to do it:
Custom matcher for a single group
If you're only going to include a matcher once, you can also use the matcher macro within an example group:
describe "group" do
matcher :be_just_like do |expected|
match {|ac...