Rails: Migration helper for inserting records without using models
You should avoid using application models in your migrations. But how else could you create records in a migration?
The most basic way is to write plain SQL, but since INSERT statements are no pleasant write for Rubyists, here is a simple wrapper:
Record creation helper for migrations
The helper method below takes a table name and a hash of attributes, which it inserts into the specified table. Copy it over to your migration and profit!
private
def insert_record(table, **attributes)
attributes.merge!...
PostgreSQL: WITH Queries (Common Table Expressions)
PostgreSQL's Common Table Expressions (CTEs) can be used to extract sub-queries from bulky SQL statements into a temporary table to be referenced instead.
This is most useful to avoid ugly joins or sub-selects. CTEs can be used for SELECT, INSERT, UPDATE or DELETE.
Example (from the PostgreSQL docs):
WITH regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
), top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (SE...
PostgreSQL's OVERLAPS operator is not fully inclusive
PostgreSQL supports the SQL OVERLAPS operator. You can use it to test if two date ranges overlap:
=> SELECT ('2001-02-16'::date, '2001-12-21'::date) OVERLAPS
('2001-12-20'::date, '2002-10-30'::date);
overlaps
--------
true
An important caveat is that the date ranges are defined as start <= time < end. As such the later date is not included in the range:
=> SELECT ('2001-02-16'::date, '2001-12-21'::date) OVERLAPS
('2001-12-21'::date, '2002-10-30'::date);
overlaps
--------
false
Also compar...
Git: creating and deleting a tag
Git has two kind of tags:
- annotated
- lightweight
Annotated tags are stored as full objects in the Git database. They’re checksummed; contain the tagger name, email, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG)
The following command will create a (lightweight) tag:
git tag v0.1
An annotated tag is created by:
git tag -a v0.1 -m "a special tag message"
A normal git push will not push the tag. So in order to publish your (local) tags, you have to
git push --tags
`...
Cucumber: Identifying slow steps that drag down your test speed
In most projects I know, Cucumber test suite speed is not an issue. Of course, running 350 features takes its time, but still each test for itself is reasonably fast. There is nothing you can do to fundamentally speed up such a test (of course, you should be using parallel_tests).
However, in projects that go beyond clicking around in a web GUI and checking results, there might be various measures to speed things up. Katapult tests for example could be sped up more than 4 times by re...
Webservice to test and inspect requests
Requestb.in is a webservice that gives you a temporary URL you can use to test request. The page will automatically record and display the latest web request made to it.
How to install packages from newer Ubuntu releases
We're usually running Ubuntu LTS versions. Sometimes newer hardware requires packages from more recent Ubuntu releases that only come with 6 months of support. If there is really no other way, it's possible to install packages from later Ubuntu releases
Caution: Pay really close attention to what you're doing. Depending on the package, this process may require upgrading a lot of dependencies, possibly breaking the system! You really should not do this unless you've carefully calculated the impact on your system
Preparation
First,...
Fixing flaky E2E tests
An end-to-end test (E2E test) is a script that remote-controls a web browser with tools like Selenium WebDriver. This card shows basic techniques for fixing a flaky E2E test suite that sometimes passes and sometimes fails.
Although many examples in this card use Ruby, Cucumber and Selenium, the techniques are applicable to all languages and testing tools.
Why tests are flaky
Your tests probably look like this:
When I click on A
And I click on B
And I click on C
Then I should see effects of C
A test like this works fine...
Be careful to use correct HTTP status codes for maintenance pages
When your public-facing application has a longer downtime for server maintenance or long migrations, it's nice to setup a maintenance page to inform your users.
When delivering the maintenance page, be very careful to send the correct HTTP status code. Sending the wrong status code might get you kicked out of Google, or undo years of SEO work.
Popular footguns
Here are some ways to shoot yourself in the foot during maintenance:
- If all your routes send a "200 OK" with a HTML body "We're b...
Async control flow in JavaScript: Promises, Microtasks, async/await
Slides for Henning's talk on Sep 21st 2017.
Understanding sync vs. async control flow
Talking to synchronous (or "blocking") API
print('script start')
html = get('/foo')
print(html)
print('script end')
Script outputs 'script start', (long delay), '<html>...</html>', 'script end'.
Talking to asynchronous (or "evented") API
print('script start')
get('foo', done: function(html) {
print(html)
})
print('script end')
Script outputs 'script start', 'script end', (long ...
How to fix broken font collisions in wkhtmltopdf
If you are using PDFKit / wkhtmltopdf, you might as well want to use custom fonts in your stylesheets. Usually this should not be a problem, but at times they include misleading Meta-information that leads to a strange error in the PDF.
The setup
- The designer gave you two fonts named something like
BrandonText-RegularandBrandonText-Bold. (With flawed Meta-information) - You have a HTML string to be rendered by PDFKit
- For demonstration purposes, this strin...
Association to polymorphic model does not determine inverse_of automatically
You need to set the :inverse_of option manually for relations that have an association to a polymorphic model. Otherwise you will not be able to save a record with a nested polymorphic association.
class Event < ApplicationRecord
has_many :letters, as: :record
end
class Letter < ApplicationRecord
belongs_to :record, polymorphic: true
end
event = Event.new.letters.build
event.save! # => ActiveRe...
RSpec: How to define classes for specs
RSpec allows defining methods inside describe/context blocks which will only exist inside them.
However, classes (or any constants, for that matter) will not be affected by this. If you define them in your specs, they will exist globally. This is because of how RSpec works (short story: instance_eval).
Negative example:
describe Notifier do
class TestRecord < ApplicationRecord # DO NOT do this!
# ...
end
let(:record) { TestRecord.new }
it { ... }
end
# TestRecord will exist here, outside of the spec!
D...
Rails: render a template that accepts a block by using the layout option of render
Let's say you have a form that you render a few times but you would like to customize your submit section each time. You can achieve this by rendering your form partial as layout and passing in a block. Your template or partial then serves as the surrounding layout of the block that you pass in. You can then yield back the form to the block and access the form in your block.
-# record/_form.haml
= form_for record do |form|
-# ...
.form-actions
yield(form)
In order to make your template record/_form.haml accept a...
How to change the class in FactoryBot traits
FactoryBot allows a :class option to its factory definitions, to set the class to construct. However, this option is not supported for traits.
Most often, you can just define a nested factory instead of a trait, and use the :class option there.
factory :message do
factory :reply, class: Message::Reply do
# ...
end
end
If you need/want to use traits instead (for example, it might make more sense semantically), you can not use a :class on a trait.
In that case, use initialize_with to define the record's constr...
How to avoid ActiveRecord::EnvironmentMismatchError on "rails db:drop"
After loading a staging dump into development, you might get an ActiveRecord::EnvironmentMismatchError when trying to replace the database (like rails db:drop, rails db:schema:load).
$ rails db:drop
rails aborted!
ActiveRecord::EnvironmentMismatchError: You are attempting to modify a database that was last run in `staging` environment.
You are running in `development` environment. If you are sure you want to continue, first set the environment using:
bin/rails db:environment:set RAILS_ENV=development
Starting with R...
Postgres: How to force database sessions to terminate
If another session is accessing your database you are trying to reset or drop you might have seen the following error:
PG::ObjectInUse: ERROR: database "foo_development" is being accessed by other users
DETAIL: There is 1 other session using the database.
This could be the rails server, rubymine and many more. Beside terminating the session connection manually you can also find out the pid and kill the process.
1. rails db
2. SELECT * FROM pg_stat_activity;
datid | 98359
datname | foo_developm...
Ruby: A small summary of what return, break and next means for blocks
Summary
- Use
returnto return from a method.returnaccepts a value that will be the return value of the method call. - Use
breakto quit from a block and from the method that yielded to the block.breakaccepts a value that supplies the result of the expression it is “breaking” out of. - Use
nextto skip the rest of the current iteration.nextaccepts an argument that will be the result of that block iteration.
The following method will serve as an example in the details below:
def example
puts yield
puts ...
Custom Ruby method Enumerable#count_by (use for quick statistics)
I frequently find myself needing a combination of group_by, count and sort for quick statistics. Here's a method on Enumerable that combines the three:
module Enumerable
def count_by(&block)
group_by(&block)
.transform_values(&:count)
.sort_by(&:last)
.to_h
end
end
Just paste that snippet into a Rails console and use #count_by now!
Usage examples
- Number of email addresses by domain:
> User.all.count_by { |user| user.email.sub /^.*@/, '' }
=> { "sina.cn"=>2, ..., "hotmail.co...
Rspec: around(:all) and around(:each) hook execution order
Background
-
before(:all)runs the block once before all of the examples. -
before(:each)runs the block once before each of your specs.
Summary
-
around(:suite)does not exist. -
around(:all)runs afterbefore(:all)and beforeafter(:all). -
around(:each)runs beforebefore(:each)and afterafter(:each).
As this is not 100% obvious (and not yet documented) it is written down in this card. In RSpec 3 :each has the alias :example and :all the alias :context.
Example
RSpec.configure do |config|
...
How to mount a legacy database to migrate data
There are many approaches out there how you can import data from a legacy application to a new application. Here is an approach which opens two database connections and uses active record for the legacy system, too:
1. Add you database information to you config/database.yml.
data_migration:
database: your_application_data_migration
2. Create a separate application record for the data migration, e.g. in app/data_migration/migration_record.rb. You will need to create an app/data_migration.rb class first.
class DataMig...
JavaScript: Polyfill native Promise API with jQuery Deferreds
You should prefer native promises to jQuery's Deferreds. Native promises are much faster than their jQuery equivalent.
Native promises are supported on all browsers except IE <=11, Android <= 4.4 and iOS <= 7.
If you need Promise support for these old browsers y...
JavaScript: How to query the state of a Promise
Native promises have no methods to inspect their state.
You can use the promiseState function below to check whether a promise is fulfilled, rejected or still pending:
promiseState(promise, function(state) {
// `state` now either "pending", "fulfilled" or "rejected"
});
Note that the callback passed to promiseState will be called asynchronously in the next [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/...