PostgreSQL and its way of sorting strings
PostgreSQL uses the C library's locale facilities for sorting strings:
- First, all the letters are compared, ignoring spaces and punctuation.
- It sorts upper and lower case letters together. So the order will be something like
a A b B c C
- Then, spaces and punctuation are compared to break ties.
Example:
Ruby | PostgreSQL |
---|---|
IMAGE3.jpg | image2.jpg |
image.jpg | image3.jpg |
image2.jpg | IMAGE3.jpg |
image3.jpg | image.jpg |
Further reading
- [PostgreSQL-FAQ: Why do my strings sort incorrectly?](h...
Run all RSpec tests edited or added in the current branch
With this command you can run all the spec files which have been edited or added in the current branch since master:
git diff --name-only master -- ./spec | xargs -I{} rspec {}
- If you have several spec folders add them for path parameter after
./spec
accordingly. - The option
-I{}
creates a placeholder to be replaced. - You can also compare edited/added specs between commits with
<commit>..<commit>
Jasmine: Use `throwUnless` for testing-library's `waitFor`
testing-library are widely used testing utilities libraries for javascript dependent frontend testing. The main utilities provided are query methods, user interactions, dom expectations and interacting with components of several frontend frameworks, which allows us to worry less about the details happening in the browser and focus more on user centric tests instead!
Some of the time you will find a necessity to use methods like [waitFor
](https://testing-library.com/docs/dom-testing-library/api-async/...
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...
Rails credentials: Always use the bang version
Rails credentials are a way to store secrets in an encrypted YAML file. Usage is simple: each key in the credentials file becomes a method on Rails.application.credentials
, returning the corresponding secret.
# Credentials file
file_storage_secret: superstrongsecret
# Somewhere in the application
FileStorage.secret = Rails.application.credentials.file_storage_secret
Since credentials usually are different between environments, you can easily forget to define them for another environment. If it is an API token, you'll...
Implementing a custom RuboCop cop
It's possible to implement simple custom RuboCop cops with very little code. They work exactly the same like existing rubocop cops and fail the pipeline if they find an offense. This is handy for project specific internal rules or conventions.
The following cop looks at every ruby file and searches for TODO
or WIP
comments and adds an offense.
class NoTodos < RuboCop::Cop::Base
MSG = "Don't add TODOs & WIPs in the source."
def on_new_investigation
processed_source.comments.each { |comment| search_for_forbidden_ann...
Be very careful with 301 and 308 redirects
Browsers support different types of redirects.
Be very careful with these status codes:
301 Moved Permanently
308 Permanent Redirect
Most browsers seem to cache these redirects forever, unless you set different Cache-Control
headers. If you don't have any cache control headers, you can never change them without forcing users to empty their cache.
Note
By default Rails sends a ...
Rails: Prefer parsing dates with Date.strptime()
It is very common to parse dates from strings. It seems obvious to use Date.parse
for this job. However this method does not validate the input and tries to guess the format of the string.
This can lead to a very unexpected results:
Date.parse('Foobar_09_2018')
# Tue, 09 Oct 2018
In most of the cases it would be better to use Date.strptime
as you can provide a date or time pattern to match against.
Date.strptime('Foobar_09_2018', '%d_%m_%Y')
# ArgumentError (invalid strptime format - `%d_%m_%Y')
Date.strptime('01_09...
Rails SQL Injection Examples
This page lists many query methods and options in ActiveRecord which do not sanitize raw SQL arguments and are not intended to be called with unsafe user input. Careless use of these methods can open up code to SQL Injection exploits. The examples here do not include SQL injection from known CVEs and are not vulnerabilites themselves, only potential misuses of the methods.
Please use this list as a guide of what not to do.
How to combine unknown CSS selectors
You are given two CSS selectors that you do not control. How can you build a new selector that matches both of them?
item_selector = 'div'
active_selector = '.is-active'
Can't I just concat these selectors?
# Bad
new_selector = "#{item_selector}#{active_selector}"
# => "div.is-active"
Don't! This will break as soon as one of the selectors is actually a selector list.
item_selector = 'div, span, p' # <- Selector list
new_selector # => "div, span, p.is-active" (wrong)
Solution
Wrap both selectors ...
JavaScript: Listening to a class getting added
Reacting on a class getting added can be done with a mutation observer. Example:
const items = document.querySelectorAll('.item')
const expectedClass = 'active'
const activeObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.target.classList.contains(expectedClass) {
// Do something
}
})
})
items.forEach(item => activeObserver.observe(item, { attributes: true, attributeFilter: ['class'] }))
Note that this is not a generic solution – it makes a few assumptions to simplif...
How to ask a (mobile) browser about the true visual viewport
The Visual Viewport API enables developers to access the actually visible area of the page. This differs from the normal viewport if:
- the user has pinch-zoomed
- the on-screen keyboard is visible
- there are other page-independent artifacts
Obtain a VisualViewport
from window.visualViewport
. The object has the properties offsetLeft
and offsetTop
, and three events: resize
, scroll
, scrollend
. You can use these to place and keep an element within the visual vi...
How to start Terminator with split screens and custom commands running
Starting Terminator with split screens is quite simple: Just store a layout and start Terminator with the --layout <your layout>
option.
However, if you want to run custom commands in your terminals, you need to do some work to keep these terminals from closing after a command exits. You accomplish this by tweaking bash to run a command before actually starting.
Pimp your .bashrc
Add this to the end of .bashrc
:
# hack to keep a bash open when starting it with a command
[[ $startup_cmd ]] && { declare +x $startup_cmd; hi...
JavaScript: Testing the type of a value
Checking if a JavaScript value is of a given type can be very confusing:
- There are two operators
typeof
andinstanceof
which work very differently. - JavaScript has some primitive types, like string literals, that are not objects (as opposed to Ruby, where every value is an object).
- Some values are sometimes a primitive value (e.g.
"foo"
) and sometimes an object (new String("foo")
) and each form requires different checks - There are three different types for
null
(null
,undefined
andNaN
) and each has different rules for...
How to Work With Time Zones in Rails
When dealing with time zones in Rails, there is one key fact to keep in mind:
Rails has configurable time zones, while
Ruby is always in the server's time zone
Thus, using Ruby's time API will give you wrong results for different time zones.
"Without" time zones
You can not actually disable time zones, because their existence is a fact. You can, however, tell Rails the only single time zone you'll need is the server's.
config.time_zone = "Berlin" # Local time zone
config.active_record.default_timezone = :loca...
Avoiding Test-Case Permutation Blowout - Steven Hicks
Sometimes you want to write a test for a business rule that's based on multiple variables. In your goal to cover the rule thoroughly, you start writing tests for each permutation of all variables. Quickly it blows up into something unsustainable. With n variables for the business rule, you get 2n permutations/test cases. This is manageable with 2 variables (4 test cases), but at 3 variables (8 test cases) it becomes ridiculous, and anything beyond that feels immediately uncomfortable.
I've noticed myself using an alternate pattern for...
A gotcha of Ruby variable scoping
I recently stumbled over a quirk in the way Ruby handles local variables that I find somewhat dangerous.
Consider:
def salutation(first_name, last_name = nil)
if last_name
full_name = "#{first_name} #{last_name}"
end
"Hi #{full_name}"
end
This is obviously wrong, full_name
is unset when last_name
is nil.
However, Ruby will not raise an exception. Instead, full_name
will simply be nil
, and salutation('Bob')
returns 'Hi '
.
The same would happen in an else
branch:
def salutation(fi...
Compare library versions as "Gem::Version" instances, not as strings
Sometimes we have to write code that behaves differently based on the version of a specific gem or the Ruby Version itself. The version comparison can often be seen with simple string comparison like so.
# ❌ Not recommended
if Rails.version > '6.1.7.8' || RUBY_VERSION > '3.1.4'
raise Error, 'please check if the monkey patch below is still needed'
end
If you are lucky, the version comparison above works by coincidence. But chances are that you are not: For example, Rails version 6.1.10.8
would not raise an error in the code ...
How to write complex migrations in Rails
Rails gives you migrations to change your database schema with simple commands like add_column
or update
.
Unfortunately these commands are simply not expressive enough to handle complex cases.
This card outlines three different techniques you can use to describe nontrivial migrations in Rails / ActiveRecord.
Note that the techniques below should serve you well for tables with many thousand rows. Once your database tables grows to millions of rows, migration performance becomes an iss...
Working on the Linux command line: Use the `tree` command instead of repeated `cd` and `ls`
The tree
command will show you the contents of a directory and all its sub directories as a tree:
>tree
.
├── a
│ ├── file_1.txt
│ └── file_2.txt
└── b
├── c
│ └── even_more.txt
└── more.txt
3 directories, 4 files
If you have deeply nested directories, the output will be quite long though. To avoid that, you can limit the depth, e.g. tree -L 2
will only go 2 directories deep.
If you use that regularly, consider adding aliases for that to your ~/.bashrc
:
alias tree2='tree -L 2'
alias tree3='tree -L 3'
...
Your browser might silently change setTimeout(f, 0) to setTimeout(f, 4)
When you're nesting setTimeout(f, 0)
calls, your browser will silently increase the delay to 5 milliseconds after the fourth level of nesting.
This is called "timeout clamping" and defined in the HTML spec:
If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.
Timeouts are clamped harder in background tabs
On a similar note, all major browsers have implemented throttling rules for setInterval
and setTimeout
calls from tabs...
How to speed up JSON rendering with Rails
I was recently asked to optimize the response time of a notoriously slow JSON API endpoint that was backed by a Rails application.
While every existing app will have different performance bottlenecks and optimizing them is a rabbit hole of arbitrary depth, I'd like to demonstrate a few techniques which could help reaching actual improvements.
The baseline
The data flow examined in this card are based on an example barebone rails app, which can be used to reproduce the r...
RubyMine: Adjust Code Templates
tl;dr
To adjust code templates in RubyMine, navigate to Settings -> Editor -> File and Code Templates.
Example
You can navigate to the test file of the currently open file with the shortcut Ctrl + T
. If no test file exists, you can generate a new test file. If you are not pleased with the output, you can adjust the related code template. To do this, open the project settings and navigate to Editor -> File and Code Templates -> Files. Now, choose your relevant file type and adjust the code template according ...
Protected and Private Methods in Ruby
In Ruby, the meaning of protected
and private
is different from other languages like Java. (They don't hide methods from inheriting classes.)
private
Private methods can only be called with implicit receiver. As soon as you specify a receiver, let it only be self
, your call will be rejected.
class A
def implicit
private_method
end
def explicit
self.private_method
end
private
def private_method
"Private called"
end
end
A.new.implicit
# => "Private called"
A.new.explicit
# => NoMethod...