JavaScript without jQuery
This is a presentation from 2019-01-21.
Summary
- We want to move away from jQuery in future projects
- Motivations are performance, bundle size and general trends for the web platform.
- The native DOM API is much nicer than it used to be, and we can polyfill the missing pieces
- Unpoly 0.60.0 works with or without jQuery
Is jQuery slow?
From: Sven
To: unpoly@googlegroups.com
Subject: performance on smartphones and tablets
Hello
I just used your framework in one project and must say,
I am really pleased with it -- but o...
Heads up: pg_restore --clean keeps existing tables
When restoring a PostgreSQL dump using pg_restore, you usually add the --clean flag to remove any existing data from tables.
Note that this only removes data from tables that are part of the dump and will not remove any extra tables. You need to do that yourself.
When is this relevant?
As an example: You want to load a staging dump into your development machine. On your development machine, you have run migrations that introduced more tables which do not yet exist on staging. pg_restore with --clean will loa...
How to drop all tables in PostgreSQL
To remove all tables from a database (but keep the database itself), you have two options.
Option 1: Drop the entire schema
You will need to re-create the schema and its permissions. This is usually good enough for development machines only.
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
Applications usually use the "public" schema. You may encounter other schema names when working with a (legacy) application's database.
Note that f...
How to upgrade Rails: Workflow advice
When upgrading Rails versions -- especially major versions -- you will run into a lot of unique issues, depending on the exact version, and depending on your app.
However, it is still possible to give some generic advice on how you want to tackle the update in principle.
If you are not really confident about upgrading Rails, have a look at Rails LTS.
How many update steps?
Besides the Rails upgrade itself, you might also want to upgrade your other gems and upgrade your Ruby version.
First decide in how many st...
Regular tasks for long-running projects
When projects run for many years, they require special regular maintenance to stay fresh. This kind of maintenance is usually not necessary for small or quick projects, but required to keep long-running projects from getting stale.
You should be able to fit this into a regular development block.
Quarterly
Check which libraries need updating
As time goes by, libraries outdate. Check your software components and decide if any of it needs an update. Your main components (e.g. Ruby, Rails, Unpoly) should always be reasonably up to da...
Rubymine FileType mismatch
If your Rubymine does not recognize a file type correctly although you have entered the unmistakeable file extension like material_orders_controller.rb, this may help you:
Causing the Problem
Sometimes you create a new file and forget to enter the ending like material_orders_controller
Rubymine handles such files per default as simple txt files.
You delete this file and create a new one with correct ending: material_orders_controller.rb. But still Rubymine treats this file as text file, no highlighting is available.
What happene...
ActiveJob Inline can break the autoloading in development
We figured out, that ActiveJob Inline might lead to autoloading problems in development. The result was an exception when running an import script, which delivers async mails.
A copy of XXX has been removed from the module tree but is still active! (ArgumentError)
Our fix was to use .deliver_now and not .deliver_later (this is not a general fix, but it was okey for us). Below there are some debug hints which helped us to locate the problem:
- We placed a pry debugger in [ActiveSupport#clear](https://github.com/rails/rails/blob...
Devise: Don't forget to lock users with soft delete
There are two ways to lock a user in devise.
- Using the lockable module
- Customizing the user account status validation when logging in.
It depends on your requirements which methods works best.
Locking a user on soft delete
We recommend to use option 2 when you want to couple the lock to the m...
RSpec 3 allows chaining multiple expectations
When you are using lambdas in RSpec to assert certain changes of a call, you know this syntax:
expect { playlist.destroy }.to change { Playlist.count }.by(-1)
While you can define multiple assertions through multiple specs, you may not want to do so, e.g. for performance or for the sake of mental overhead.
Multiple expectations on the same subject
RSpec allows chaining expectations simply by using and.
expect { playlist.destroy }
.to change { Playlist.count }.by(-1)
.and not_change { Video.count }
...
cucumber_factory 1.14 lets you set array fields, has_many associations, numbers without quotes
Setting array columns
When using PostgreSQL array columns, you can set an array attribute to a value with square brackets:
Given there is a movie with the tags ["comedy", "drama" and "action"]
Setting has_many associations
You can set has_many associations by referring to multiple named records in square brackets:
Given there is a movie with the title "Sunshine"
And there is a movie with the title "...
Minify Font Awesome fonts with webpack
Font Awesome 5 is a comprehensive solution for vector icons on your website.
Originally, Font Awesome came as an icon font (plus stylesheets), but recently it can also be used as a pure JavaScript solution (which will render icons as inline <svg> tags), or even as SVG sprites.
All solutions have their pros and cons:
Icon font:
- little CPU load (no JavaScript)
- fonts are relatively large
- 1 extra HTTP request
Javascript + inline SVG:
- higher CPU load (needs to watch the DOM via mutation observers to ad...
How to let passenger restart after deployment with capistrano
Phusion Passenger changed the way how it gets restarted several times. Through the project's history, these all were valid:
touch tmp/restart.txtsudo passenger-config restart-app /path/to/apppassenger-config restart-app /path/to/app
You should not need to know which one to use. Instead, the capistrano-passenger gem will choose the appropriate restart mechanism automatically based on your installed the passenger version.
Installation
-
Add to your
Gemfile:gem 'capistr...
An incomplete guide to migrate a Rails application from paperclip to carrierwave
In this example we assume that not only the storage gem changes but also the file structure on disc.
A general approach
Part A: Create a commit which includes a script that allows you to copy the existing file to the new file structure.
Part B: Create a commit which removes all paperclip logic and replace it with the same code you used in the first commit
Part A
Here are some implementation details you might want to reuse:
- Use the existing models to read the files from
- Use your own carrierwave models to write t...
Colcade is a lightweight Masonry alternative
Masonry is a famous library to dynamically arrange a grid of items that have different aspect ratio, like horizontal and vertical images.
Colcade is an alternative masonry-layouting library, developed by the same developer, but with a more modern approach.
It is said to have better performance while being smaller and having no dependencies. It automagically detects jQuery and defines a jQuery initializer, if present.
However, it offers [a few less features](https:...
Geordi: How to rerun failed features
Geordi's cucumber command has a --rerun option that reruns failing tests the given number of times. Usage:
geordi cucumber path/to/features --rerun=2
geordi cucumber path/to/features -r2
Background and how to rerun manually
Cucumber will save a file tmp/parallel_cucumber_failures.log containing the filenames and line number of the failed scenarios after a full test run. Normally you can say cucumber -p rerun (rerun is a profile defined by default in config/cucumber.yml) to rerun all failed scenarios.
Here are a few al...
Rails < 5: How to get after_commit callbacks fired in tests
If you use transactional_fixtures or the database_cleaner gem with strategy :transaction, after_commit callbacks will not be fired in your tests.
Rails 5+
Rails 5 has a fix for this issue and no further action is needed.
Rails 3, Rails 4
Add the gem test_after_commit to your test group in the Gemfile and you are done. You don't need to change the database strategy to deletion (wh...
Rails: How to check if a certain validation failed
If validations failed for a record, and you want to find out if a specific validation failed, you can leverage ActiveModel's error objects.
You rarely need this in application code (you usually just want to print error messages), but it can be useful when writing tests.
As an example, consider the following model which uses two validations on the email attribute.
class User < ApplicationRecord
validates :email, presence: true, uniqueness: true
end
Accessing errors
Let's assume we have a blank user:
user = Us...
How to write a good changelog
We want to keep a changelog for all gems we maintain. There are some good practices for writing a changelog that adds value, please stick to these.
- Add a notice to the README's contribute section about the changelog
- For every release update the changelog
- Note the date format yyyy-mm-tt
What is a changelog?
A changelog is a file which contains a curated, chronologically ordered list of notable changes for each version of a project.
Why keep a changelog?
To make it easier for users and...
HTML forms with multiple submit buttons
Most forms have a single submit button that will save the record when pressed.
Sometimes a form needs additional submit buttons like "accept" or "reject". Such buttons usually attempt a state transition while updating the record.
To process a form with multiple buttons, your server-side code will need to know which button was pressed. To do so you can give each submit button a different [formaction] attribute. This will override the ...
SSH: X-Forwarding
If you need to run a program on a remote machine (e.g. to your office PC) with a graphical UI (and you trust the remote machine), you can use SSH X-Forwarding. I sometimes use this to connect to a virtual machine installed on my work PC from my home office.
Forwarding X over SSH
To use X forwarding, when connecting to the remote machine, and add -X to the ssh call. Now, when you start a program with a UI (e.g. virtualbox) in that SSH session, a window will open on your local machine. It will not be particularly ...
Best practices: Large data migrations from legacy systems
Migrating data from a legacy into a new system can be a surprisingly large undertaking. We have done this a few times. While there are significant differences from project to project, we do have a list of general suggestions.
Before you start, talk to someone who has done it before, and read the following hints:
Understand the old system
Before any technical considerations, you need to understand the old system as best as possible. If feasible, do not only look at its API, or database, or frontend, but let a user of the old system sho...
Project management best practices: The story tracker
In general, the tracker should always be the definitive source of truth of what needs to be done as part of a project. If you identify a task that needs to be done, you should create a story. If you learn something that contradicts an existing story, change it.
The tracker can contain two types of stories: Developer stories, and non-developer stories.
Non-developer stories
Non-developer stories should be clearly marked. They usually belong to the PM (or maybe people from the operations team). Those story can take all forms, could just...
Chrome bug: Wrong stacking order when transitioning composited elements
Google Chrome has a subtle rendering bug that hits me once in a while. It usually occurs in sliders with HTML content.
The issue
When a slider contains a composited[1] element, the element will overlap any other element when sliding, being rendered as frontmost element. After the slider has settled, stacking order jumps back to normal.
It seems like Chrome is doing its compositing wrong. This doesn't happen in Firefox.
The cause
The issue only occurs if:
- two elements A and B are nested inside an element C
- A overlaps B (part...
Haml: Generating a unique selector for an element
Having a unique selector for an element is useful to later select it from JavaScript or to update a fragment with an Unpoly.
Haml lets you use square brackets ([]) to generate a unique class name and ID from a given Ruby object. Haml will infer a class attribute from the given object's Ruby class. It will also infer an id attribute from the given object's Ruby class and #id method.
This is especially useful with ActiveRecord instances, which have a persisted #id and will hence **generate the same selector o...