Video transcoding: Web and native playback overview (April 2020)
Intro
Embedding videos on a website is very easy, add a <video> tag to your source code and it just works. Most of the time.
The thing is: Both the operating system and Browser of your client must support the container and codecs of your video. To ensure playback on every device, you have to transcode your videos to one or more versions of which they are supported by every device out there.
In this card, I'll explore the available audio and video standards we have right now. The goal is to built a pipeline that...
Git diff: Deemphasizing code that was only moved around
In long diffs, it can become impossible to spot small changes in larger blocks of moved code. This may be either a method that was moved from the top to the bottom of a file, or a long test file that was split in many.
Fortunately, Git offers a special highlighting mode that directs the reader's attention to relevant code parts:
git diff --color-moved=dimmed-zebra
It will dim lines that were moved around without changes, and highlight changed lines.
To easily use dimmed-zebra mode, configure an alias:
# ~/.gitconfig
[alias]
...
RSpec: Executing specs by example id (or "nesting index")
There are several ways to run a single spec. I usually copy the spec file path with the line number of the example and pass it to the RSpec binary: bin/rspec spec/models/user_spec.rb:30 (multiple line numbers work as well: :30:36:68). Another is to tag the example with focus: true or to run the example by matching its name.
In this card I'd like to ...
Spreewald, Cucumber: Selector for the nth Element
The recommended additional setup of the spreewald gem, a useful set of cucumber steps, includes adding a file for defining custom selectors which can be used as prose within steps:
When I follow "Edit" within the controls section
Where the controls section can be any arbitrary defined css selector within selectors.rb
Often it can be useful to select the nth element of a specific selector. Luckily, this can ...
RSpec: automatic creation of VCR cassettes
This RailsCast demonstrated a very convenient method to activate VCR for a spec by simply tagging it with :vcr.
For RSpec3 the code looks almost the same with a few minor changes. If you have the vcr and webmock gems installed, simply include:
# spec/support/vcr.rb
VCR.configure do |c|
c.cassette_library_dir = Rails.root.join("spec", "vcr")
c.hook_into :webmock
end
RSpec.configure do |c|
c.around(:each, :vcr) do |example|
name = example.metadata[:full_descripti...
RSpec's hash_including matcher does not support nesting
You can not use the hash_including argument matcher with a nested hash:
describe 'user' do
let(:user) { {id: 1, name: 'Foo', thread: {id: 1, title: 'Bar'} }
it do
expect(user).to match(
hash_including(
id: 1, thread: {id: 1}
)
)
end
end
The example will fail and returns a not very helpful error message:
expected {:id => 1, :name => "Foo", :thread => {:id => 1, :title => "Bar"}} to...
Check that an element is hidden via CSS with Spreewald
If you have content inside a page that is hidden by CSS, the following will work with Selenium, but not when using the Rack::Test driver. The Selenium driver correctly only considers text that is actually visible to a user.
Then I should not see "foobear"
This is because the Rack::Test driver does not know if an element is visible, and only looks at the DOM.
Spreewald offers steps to check that an element is hidden by CSS:
Then "foo" should be hidden
You can also check that an el...
Why preloading associations "randomly" uses joined tables or multiple queries
ActiveRecord gives you the :include option to load records and their associations in a fixed number of queries. This is called preloading or eager loading associations. By preloading associations you can prevent the n+1 query problem that slows down a many index view.
You might have noticed that using :include randomly seems to do one of the following:
- Execute one query per involved table with a condit...
How to evaluate CSS media queries in JavaScript
To make CSS rules dependent on the screen size, we use media queries:
@media (max-width: 500px) {
// rules for screen widths of 500px or smaller
}
Browsers will automatically enable and disable the conditional rules as the screen width changes.
To detect responsive breakpoints from JavaScript, you may use the global matchMedia() function. It is supported in all brow...
What we know about PDFKit
What PDFKit is
- PDFKit converts a web page to a PDF document. It uses a Webkit engine under the hood.
- For you as a web developer this means you can keep using the technology you are familar with and don't need to learn LaTeX. All you need is a pretty print-stylesheet.
How to use it from your Rails application
- You can have PDFKit render a website by simply calling
PDFKit.new('http://google.com').to_file('google.pdf'). You can then send the...
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...
Rails: Example on how to extract domain independent code from the `app/models` folder to the `lib/` folder
This cards describes an example with a Github Client on how to keep your Rails application more maintainable by extracting domain independent code from the app/models folder to the lib/ folder. The approach is applicable to arbitrary scenarios and not limited to API clients.
Example
Let's say we have a Rails application that synchronizes its users with the Github API:
.
└── app
└── models
├── user
│ ├── github_client.rb
│ └── sychronizer.rb
└── user.rb
In this example the app folder ...
Sass: How to get rid of deprecation warnings in dependencies
sass >= 1.35.0 has the option quietDeps and silenceDeprecations to silence deprecation warnings from dependencies.
-
quietDeps: No deprecation warnings for dependencies e.g. Bootstrap -
silenceDeprecations: Allows to set a list of deprecation types you want to silence for your own code
Below there are a few examples for different build tools how to set the Sass options.
Webpacker
const sassLoaderConfig = environment.loaders.get('sass')
const...
Use CSS "text-overflow" to truncate long texts
When using Rails to truncate strings, you may end up with strings that are still too long for their container or are not as long as they could be. You can get a prettier result using stylesheets.
The CSS property text-overflow: ellipsis has been around for quite a long time now but since Firefox did not support it for ages, you did not use it. Since Firefox 7 you can!
Note that this only works for single-line texts. If you want to truncate tests across multiple lines, use a JavaScript solution like...
How to run a small web server (one-liner)
Sometimes you just want to have a small web server that serves files to test something.
Serve the current directory
On Ruby 1.9.2+ you can do the following ("." for current directory). You might need to gem install webrick on modern Rubies.
ruby -run -ehttpd . -p8000
Python 2.x offers a similar way.
python -m SimpleHTTPServer 8000 .
This is the same way with Python 3.x
python -m http.server
In both cases your web server is single-threaded and will block when large files are being downloaded from you.
WEBrick ...
Rails: Rest API post-mortem analysis
This is a personal post-mortem analysis of a project that was mainly build to provide a REST API to mobile clients.
For the API backend we used the following components:
- Active Model Serializer (AMS) to serializer our Active Record models to JSON.
- JSON Schema to test the responses of our server.
- SwaggerUI to document the API.
It worked
The concept worked really good. Here are two points that were extraordinary compared to normal Rails project with many UI components:
- Having a Rails application, that has no UI components (only...
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::Baseobjects really want to get their arguments processable as keyword arguments. Don't change the syntax, or y...
Automatic Log Rotation in Rails
Rails log files rotate automatically when they reach approx. 100MB:
$ ls -lh log/
-rw-r--r-- 1 user group 55M Sep 15 09:54 development.log
-rw-r--r-- 1 user group 101M Aug 22 13:45 development.log.0
This behavior is a built-in feature of Ruby's standard Logger class, which Rails uses by default.
To control the maximum file size, set config.log_file_size in yo...
Simple database lock for MySQL
Note: For PostgreSQL you should use advisory locks. For MySQL we still recommend the solution in this card.
If you need to synchronize multiple rails processes, you need some shared resource that can be used as a mutex. One option is to simply use your existing (MySQL) database.
The attached code provides a database-based model level mutex for MySQL. You use it by simply calling
Lock.acquire('string to synchronize on') do
# non-th...
How to: Upgrade CarrierWave to 3.x
While upgrading CarrierWave from version 0.11.x to 3.x, we encountered some very nasty fails. Below are the basic changes you need to perform and some behavior you may eventually run into when upgrading your application. This aims to save you some time understanding what happens under the hood to possibly discover problems faster as digging deeply into CarrierWave code is very fun...
Whitelists and blacklists
The following focuses on extension allowlisting, but it is the exact same thing for content type allowlisting with the `content_ty...
Opt out of selenium manager's telemetry
If you use the selenium-webdriver gem, it will sneakily phone home once every hour whenever you run a browser based feature spec.
Check if you're affected
Check if ~/.cache/selenium/se-metadata.json exists. (It contains a "ttl" timestamp of its last/next anaytics call. You can parse it with Ruby's Time.at.)
Opt out
You can opt out either globally:
# .bashrc
export SE_AVOID_STATS=true
or project based
# spec_helper...
Capybara: Pretending to interact with the document
Browsers blocks abusable JavaScript API calls until the user has interacted with the document. Examples would be opening new tab or start playing video or audio.
E.g. if you attempt to call video.play() in a test, the call will reject with a message like this:
NotAllowedError: play() failed because the user didn't interact with the document first. https://goo.gl/xX8pDD
Workaround
To pretend document interaction in a test you can create an element, click on it, and remove the element again. This unblocks the entire JavaSc...
Switch to a recently opened tab with Cucumber
Similar to closing an opened browser window, spreewald now supports the I switch to the new browser tab step.
Info
See the Spreewald README for more cool features.
You can use it to test links that were opened with a link_to(..., :target => '_blank') link or other ways that create new tabs or windows.
Important
This only works with
Selenium...
Bash script to list git commits by Linear ID
As we're switching from PT to Linear, I've updated the existing bash script to work for commits that are referencing Linear IDs.
A core benefit of our convention to prefix commits by their corresponding issue ID is that we can easily detect commits that belong to the same issue. You can either do that manually or use the bash script below. It can either be placed in your .bashrc or a...