Carrierwave: Custom file validations inside custom Uploaders
Carrierwave's BaseUploader
can have some validations that you can use by overriding a certain method, which's expected name is hard coded. A popular example is extension_allowlist
, which returns an array of strings and let's you only upload files that have a filename with an extension that matches an entry in that array. Another useful validation can be size_range
, which gives you a little bit of control over how your storage gets polluted.
This is often good enough, but some times you need to validate special cases.
Validations t...
Rails: Encrypting your database information using Active Record Encryption
Since Rails 7 you are able to encrypt database information with Active Record. Using Active Record Encryption will store an attribute as string in the database. And uses JSON for serializing the encrypted attribute.
Example:
-
p
: Payload -
h
: Headers -
iv
: Initialization Vector -
at
: Authentication Tag
{ "p": "n7J0/ol+a7DRMeaE", "h": { "iv": "DXZMDWUKfp3bg/Yu", "at": "X1/YjMHbHD4talgF9dt61A=="} }
Note this before encrypting attributes with Active Record:
...
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 describe
command 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
DISTINCT
statement. -
To retrieve the group wise maximum of certain columns: You can keep only one record for each group with the
DISTINCT ON
statement, 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:
...
Heads up: expect(object).to receive(:method_name) does not execute the original implementation of the method
Let's assume that we have a model Movie
that registers a callback function when a new instance of Movie
is created (Note: For the purpose of this card it is not important what that callback does or which type of callback it is).
This is how we test whether the callback function (here it is named :my_method
) is called when a new movie is created:
expect_any_instance_of(Movie).to receive(:my_method)
create(:movie) # <-- this is where the method :my_method should be called
You might expect that when calling `create(:mo...
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.
Why Sidekiq Jobs should never be enqueued in an `after_create` or `after_save` callback
When an object is created / updated, various callbacks are executed in this order:
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit / after_rollback
Thus, each of these callbacks is executed at a specific time in the life cycle of the object. This is important because this point in time determ...
Ruby object equality
TLDR
if you define a equality method for a class you must also implement
def hash
.
Ruby has a lot of methods that have to do something with equality, like ==
, ===
, eql?
, equal?
. This card should help you differentiate between those and give you hints on how to implement your own equality methods in a safe manner.
Differences between the methods
for everyday use: ==
When you compare two objects in ruby, you most often see the use of foo == bar
. By default the ==
operator inherits from Object
and is impl...
Bookmarklet: cards Markup Link Bookmarklet
The cards editor has a feature "Cite other card" to create links to other cards in the same deck as mardown links.
If you want to reference a card from a different deck, this bookmarklet might be useful:
javascript:(function () {
const doAlert = () => { alert("Maybe not a makandra card?") };
let cardsPathPattern = /(\/[\w-]+\/\d+)-.+/;
if (window.location.pathname.match(cardsPathPattern)) {
let currentPath = window.location.pathname.match(cardsPathPattern)[1];
let title = document.querySelector('h1.note--title')?.textCon...
Rails: Use STI in Migration
tl;dr
You should decouple migrations from models by embedding models into the migration. To use STI in this scenario you have to overwrite
find_sti_class
andsti_name
.
Tip
When possible, try to avoid STI in migrations by disabling it.
Example
Warning
This is more for the sake of I want to do it but I kno...
Jasmine: Creating DOM elements efficiently
Jasmine specs for the frontend often need some DOM elements to work with. Because creating them is such a common task, we should have an efficient way to do it.
Let's say I need this HTML structure:
<ul type="square">
<li>item 1</li>
<li>item 2</li>
</ul>
This card compares various approaches to fabricating DOM elements for testing.
Constructing individual elements
While you can use standard DOM functions to individually create and append elements, this is extremely verbose:
let list = document.createElement('...
Variable fonts: Is the performance trade-off worth it? - LogRocket Blog
Variable fonts are popular for two reasons: they expand design possibilities and improve website performance. While the former statement is definitely true since variable fonts do provide infinite typographical choices, the latter only holds under certain conditions.
Chrome DevTools: Treasure (Overview)
tl;dr
The Chrome DevTools are a neat collection of tools for the daily work as a web developer. If you're lucky, you'll maybe find some handy stuff in here.
Analysing
Breakpoints
- [Breakpoints on HTML Elements](https://makandracards.com/makandra/517982-chrome-devtools...
ActiveType::Object: Be careful when overriding the initialize method
Background:
ActiveType::Object
inherits from ActiveRecod::Base
and is designed to behave like an ActiveRecord Object, just without the database persistence.
Don't remove any of the default behavior of the initialize method!
If you have a class which inherits from ActiveType::Object
and you need to override the #initialize
method, then you should be really careful:
- Always pass exactly one attribute.
ActiveRecod::Base
objects really want to get their arguments processable as keyword arguments. Don't change the syntax, or y...
Debug flaky tests with an Unpoly observeDelay
The problem
Unpoly's [up-observe]
, [up-autosubmit]
and [up-validate]
as well as their programmatic variants up.observe()
and up.autosubmit()
are a nightmare for integration tests.
Tests are usually much faster than the configured up.form.config.observeDelay
. Therefore, it may happen that you already entered something into the next field before unpoly updates that field with a server response, discarding your changes.
The steps I wait for active ajax requests to complete
(if configured) and capybara-lockstep can catch some ...
Rails: Validations of Dates, Numerics and Strings with ComparisonValidator
tl;dr
Since Rails
7+
you can useComparisonValidator
for validations likegreater_than
,less_than
, etc. on dates, numerics or strings.
Example
We have a model for booking a trip. This model has mandatory attributes to enforce dates for the start and the end.
# == Schema Information
#
# start_date :date
# end_date :date
# ...
class TripBooking < ApplicationRecord
validates :start_date, presence: true
validates :end_date, presence: true
end
These validations are enough. We also want to ensure, th...
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...
Statistics and Reports on Web Performance Optimization
Case studies and experiments demonstrating the impact of web performance optimization (WPO) on user experience and business metrics.
Careful: `fresh_when last_modified: ...` without an object does not generate an E-Tag
To allow HTTP 304 responses, Rails offers the fresh_when
method for controllers.
The most common way is to pass an ActiveRecord instance or scope, and fresh_when
will set fitting E-Tag
and Last-Modified
headers for you. For scopes, an extra query is sent to the database.
fresh_when @users
If you do not want that magic to happen, e.g. because your scope is expens...
Rails: Custom validator for "only one of these" (XOR) presence validation
For Rails models where only one of multiple attributes may be filled out at the same time, there is no built-in validation.
I've seen different solutions in the wild, each with different downsides:
- Private method referenced via
validate
: works, but is barely portable and clutters the model. - Multiple presence validations with "if other is blank" each: looks pretty, but is incorrect as it allows both values to be filled in; also the error messages for a blank record are misleading.
Here is a third option: Write a custom validator to ...
Creating a Rails application in a single file
Greg Molnar has written a neat article about creating a single-file Rails app.
This is not meant for production use but can be useful to try things out, e.g. when hunting down a bug or embedding a Rails app into the tests of a gem.
What you do is basically:
- Put everything (gems, application config, database migrations, models, controllers) into a single
.ru
file, likeapp.ru
. - Run it via
rackup app.ru
. (Hint: if your file is calledconfig.ru
, you can just run `rac...
Git: Removing feature branches on merge
When working with feature branches, stale branches pile up over time. It's best to remove them right after merge, locally and on the remote, but it is a little tedious: you need to remember it, and perform the few steps manually each time.
Enter Git hooks. The folks at Liquid Light have built a little post-merge hook that will delete a feature branch on confirmation....
Rails: Fixing the memory leak / performance issues in prepend_view_path
Recently we detected a memory leak in one of our applications. Hunting it down, we found that the memory leak was located in Rails' #prepend_view_path
. It occurs when the instance method prepend_view_path
is called in each request, which is a common thing in a multi-tenant application.
On top of leaking memory, it also causes a performance hit, since templates rendered using the prepended view path will not be cached and compiled anew on each request.
This is not a new memory leak. It was [first reported in in 2014](https://github.com/...
A short overview of common design patterns implemented within Rails
The linked content includes a few design patterns implemented with Ruby on Rails.
What is the card indented to achieve?
- You can use the pattern names for code reviews, so all parties know with only a few words which change is requested. Example: "Please use a form object here"
- You can learn about new code patterns
- You should read the sections "Advantages of using design patterns" and "Disadvantages of using design patterns in a wrong way", since design patterns do not replace good code
Included Design Patterns: Service, Value objec...