Sending newsletters via rapidmail with SMTP and one-click unsubscribe
If you need to implement newsletter sending, rapidmail is a solid option.
Support is very fast, friendly and helpful, and the initial setup is simple. Since rapidmail works via SMTP, you can simply ask the Ops team to configure SMTP credentials for your application.
You also do not need to use rapidmail’s built-in newsletter feature. Instead, you can send emails as transactional mails, which allows you to keep the entire newsletter logic inside your application.
One thing to keep an ey...
Careful when using Time objects for generating ETags
You can use ETags to allow clients to use cached responses, if your application would send the same contents as before.
Besides what "actually" defines your response's contents, your application probably also considers "global" conditions, like which user is signed in:
class ApplicationController < ActionController::Base
etag { current_user&.id }
etag { current_user&.updated_at }
end
Under the hood, Rails generates an ETag header value like W/"f14ce3710a2a3187802cadc7e0c8ea99". In doing so, all objects from that etagge...
Rails developers: Have better context in Git diffs
Git diffs show the surrounding contexts for diff hunks. It does so by applying regular expressions to find the beginning of a context. When it comes to Ruby, however, it will not find method heads and travel up to the class definition:
@@ -24,7 +24,7 @@ class TicketPdf # <=== Actually expected here: the method definition
ApplicationController.render(
"tickets/index.html.haml",
layout: "tickets",
- assigns: { tickets: tickets }
+ assigns: { tickets: tickets, event_name: event_name }
)
end
end
```...
Deterministic ordering of records by created_at timestamp
Creating records in specs can be so fast that two records created instantly after one another might have the same created_at timestamp (especially since those timestamps don't have an indefinitely high resolution). When ordering lists by timestamps, you should therefore always include a final order condition using the primary key of the table.
class Photo < ActiveRecord::Base
scope :by_date, -> { order('created_at DESC, id DESC') }
end
Photo.by_date
Remember to include the id field in the database index.
TypeScript: Enable strict-boolean-expressions for Safe Nullish Checks
You may remember to use the || operator with caution to set defaults. We'll see that && and other conditionals come with the same limitations. However, TypeScript and eslint can make this a lot safer for us.
TL;DR
-
&&can be used as non-null safe access -
||can be used fornull/undefinedfallback values - Danger: falsey values give false negatives and bypass checks wrongly
- Prefer
??(nullish coalescing) or enablestrict-boolean-expressions...
Ruby: How to use prepend for cleaner monkey patches
Let's say you have a gem which has the following module:
module SuperClient
def self.foo
'Foo'
end
def bar
'Bar'
end
end
For reasons you need to override foo and bar.
Keep in mind: Your code quality is getting worse with with each prepend (other developers are not happy to find many library extensions). Try to avoid it if possible.
- Add a
lib/ext/super_client.rbto your project (see How to organize monkey patches in Ruby on Rails projects) - Add the extension, which ov...
Defining new elements for your HTML document
Browsers come with a set of built-in elements like <p> or <input>. When we need a new component not covered by that, we often build it from <div> and <span> tags. An alternative is to introduce a new element, like <my-element>.
When a browser encounters an unknown element like <my-element>, the browser will proceed to render <my-element>'s children. The visual rendering of your page will not be affected.
Tip
If you care about their HTML being valid, your new element should contain a dash character (
-) to mark it as a ...
How to reload a belongs_to association
To reload a single-item association in Rails 5+, call #reload_<association>:
post.reload_author
In older Railses you can say
post.author(true)
Locally testing a website on its real domain
In rare circumstances, you want to use a websites full domain (say https://mywebsite.com) while testing in dev mode. This can be useful if you need to test third party integrations like embeds, cookie banners, Google Tag Manger or other integrations that allowlist your actual domain.
To achieve this, we will have to
- make our system resolve
mywebsite.comtolocalhost, - run a reverse proxy on
localhost:443with a (locally signed and accepted) SSL certificate formywebsite.com, - forward the traffic to our actual dev server.
On l...
TypeScript: Get in Shape with Structural Typing
TypeScript basically uses structural typing, which is conceptually quite similar to duck typing, but with static compile-time type checking. We'll explore what this means in practice.
TypeScript is a superset of JavaScript, meaning TypeScript compiles down to native JavaScript syntax and checks type consistency only at compile time.
Idea of Structural Typing
TypeScript only wants to know whether the shapes of two objects are identical:
interface Point2D {
x: number;
y: number;
}
function printPoint(p: Point2D) {
c...
RSpec: Debug flickering test suites with rspec --bisect
In modern default RSpec configurations, your tests are usually run in random order. This helps to detect "flickering" tests that only fail when run in a certain order.
The reason for this are tests that have side effects causing other tests to fail later. The hard part is to find the offending test.
Enter rspec --bisect:
- Say you have a flickering test that passes on its own, but you just saw it fail in a full test run. At the top of the RSpec output, you will see a message like
Randomized with seed 12345. Take a note of the number....
Passive event listeners may speed up your scroll and touch events
Scroll and touch event listeners tend to be computationally expensive as they are triggered very often. Every time the event is fired, the browser needs to wait for the event to be processed before continuing - the event could prevent the default behavior. Luckily there is a concept called passive event listeners which is supported by all modern browsers.
Below are the key parts quoted from WICG's explainer on passive event listeners. See [this demo video](https://www.youtube.com/watch?v=NPM6172...
Linux: Open a file with the default application
If you are on a Linux shell and want to open a file with whatever default application is configured for that type, this often works:
xdg-open Quote.odt
xdg-open invoice.pdf
xdg-open index.html
Pro Tip
Make an alias so you have a simpler API (like Mac OS): alias open=xdg-open or alias x=xdg-open.
Background
You can choose your "Default applications" via UI in the Ubuntu "Settings" application (gnome-control-center). This is just a very rough setting (e.g. open Photos with Shotwell Viewer).
If a certain file...
RSpec: How to retry examples
In some projects we have issues with flaky tests. The best default is to fix them all. But in some cases it might be a pragmatic way to retry them for a limit number of times.
Notes:
- This setup was tested with a CI Pipeline that uses knapsack for parallel test balacing
- The official docs recommend to use rspec-retry, but we preferred the maintained fork rspec-rebound
**...
Git: Improve your commits by reviewing changes one-by-one
Git commits should be very deliberate, and only contain changes that you really want to be in there. In order to reduce the chance to accidentally commit something you didn't intend, review your changes before committing.
My preferred way of doing this is (only using git)
git add --intent-to-add . # Add all paths (including new files), but not their contents
git add -p
Git will now show you all your changes in small chunks and ask you in an interactive mode whether you really want to add them.
The most helpful commands ...
Heads up: JavaScript does not like big numbers
In a JavaScript console, type this:
> 9112347935156469760
9112347935156470000
Ooops. And that's not a float!
This occurs because JavaScript uses double precision floats to store numbers.
So according to IEEE floating point definition only numbers between -(2^53 - 1) (-9007199254740991) and 2^53 - 1 (9007199254740991) can safely be represented in JavaScript.
Number.MAX_SAFE_INTEGER will return the largest integer that can accurately be represented.
**For arbitrary large n...
CSS: The inset CSS shorthand
The inset CSS property is a shorthand that corresponds to the top, right, bottom, and/or left properties. It has the same multi-value syntax of the margin shorthand.
Example
<div class="outer">
<div class="inner">
Some text
</div>
</div>
.outer {
background-color: cyan;
position: relative;
width: 500px;
height: 500px;
}
Top, right, bottom and left
https://jsfiddle.net/jqx68wem/
.inner {
background-color: darkCyan;
position: absolute;
top: 10px;
right: 10px;
bottom: 10p...
How to simulate limited bandwidth in Google Chrome and Firefox
Your development machine is usually on a very good network connection.
To test how your application behaves on a slow network (e.g. mobile), you can simulate limited bandwidth.
Chrome
- Open the dev tools (Ctrl+Shift+I or F12) and switch to the "Network" tab
- In the row below the dev tool tabs, there's a throttling dropdown which reads "Online" by default.
- Inside the dropdown, you will find a few presets and an option to add your own download/upload/latency settings.
Firefox
- Open the dev tools (Ctrl+Shift+I or F12) and switc...
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...
Updated: Bash functions to provide repository context for LLM chats
Documented a repomix that allows you to bundle the XML repository context with custom LLM instructions. I have mine located at ~/.config/repomix/instruction.md
ActiveRecord: Cleaning up your database with ignored_colums
Leaving old unused DB columns around after a migration is confusing for other developers. However, dropping columns too eagerly might also cause problems and extra work. If you want to mark columns for future deletion, but you are unsure, whether you can simply drop them right now, use these tools:
Add a comment to your DB schema
With schema comments you can add a comment like LEGACY as of yyyy-mm-dd to your DB schema.
Ignore the column
With [...
Updated: Jasmine: Fixing common errors during initialization
- Added patch for Jasmine 6.0
Debugging failed AJAX requests with better_errors
better_errors is an awesome gem for enhanced error pages in development, featuring a live-REPL for some light debugging.
To debug the exception you got on an AJAX-Request, visit /__better_errors on your app's root path (e.g. http://localhost:3000/__better_errors). It shows the error page for the last exception that occurred, even when it has been triggered by an AJAX request.
You can even open files from better_errors with RubyMine on Linux.
Using partials in Rails views
Rails partials have a lot of "hidden" features and this card describes some non-obvious usages of Rails Partials.
Rendering a basic partial
The most basic way to render a partial:
render partial: 'weather'
This will render a _weather.html.erb file. Notice how all partials need to be prefixed with _.
It's possible to define local variables that are only defined in the partial template.
# _weather.html.erb
<h1>The weather is <%= condition %></h1>
# index.html.erb
render partial: 'weather', locals: { condition: ...