rbenv: A basic introduction
Why
We have projects that have been developed using many different versions of Ruby. Since we do not want to constantly update every old project, we need to have many Ruby versions installed on our development machines.
Rbenv does that for us.
How it works
Rbenv installs ruby version and ruby gems to ~/.rbenv/versions/VERSION_NUMBER/...
. This way many different Rubies can be installed at once.
When you run ruby
or gem
or bundler
or any other Ruby binary
- rbenv looks for a file...
JSONP for Rails
The rack-contrib gem brings a JSONP middleware that just works™. Whenever a JSON request has a callback
parameter, it will wrap the application's JSON response appropriately.
The project is a bit dated, but the JSONP middleware is ok.
Sass: Don't put CSS rules into partials that you import multiple times
TLDR: When you put CSS rules into a partial and import that partial multiple times, the CSS rules will be duplicated in the compiled CSS.
Here is a Sass partial called _fonts.sass
that contains both CSS rules and a mixin:
@font-face
font-family: SuperType
src: url('supertype.woff')
=title-font
font-family: SuperType
This _fonts.sass
is not practical in CSS projects that are organized over multiple files: When you...
How to tackle complex refactorings in big projects
Sometimes huge refactorings or refactoring of core concepts of your application are necessary for being able to meet new requirements or to keep your application maintainable on the long run. Here are some thoughts about how to approach such challenges.
Break it down
Try to break your refactoring down in different parts. Try to make tests green for each part of your refactoring as soon as possible and only move to the next big part if your tests are fixed. It's not a good idea to work for weeks or months and wait for all puzzle pieces ...
An Introduction to Sending HTML Email for Web Developers
A comprehensive introduction to sending HTML emails.
Intro:
HTML email: Two words that, when combined, brings tears to a developer’s eyes. If you’re a web developer, it’s inevitable that coding an email will be a task that gets dropped in your lap at some time in your career, whether you like it or not. Coding HTML email is old school. Think back to 1999, when we called ourselves “webmasters” and used Frontpage, WYSIWYG editors and tables to mark up our websites.
Table of Contents
- Introduction To Sending Email Link
- Email List B...
Passenger 5/6 requires a config.ru file to run Rails 2.3 projects
Put the following into config.ru
in your Rails root folder:
# Require your environment file to bootstrap Rails
require ::File.dirname(__FILE__) + '/config/environment'
# Dispatch the request
run ActionController::Dispatcher.new
Otherwise, your Rails 2.3 project will not be considered by Passenger 5+ and you will probably see 403 errors returned by nginx or Apache.
Aruba: Stubbing binaries
When testing your command line application with Aruba, you might need to stub out other binaries you don't want to be invoked by your test.
Aruba Doubles is a library that was built for this purpose. It is not actively maintained, but works with the little fix below.
Installation
Install the gem as instructed by its README, then put this Before
block somewhere into features/support
:
Before do
Arub...
Copy to clipboard without flash (clipboard.js)
We used zeroclipboard.js
in some of our projects but now we switched to clipboard.js
because it does not rely on flash. Flash support of the major browsers has ended.
Some more advantages of clipboard.js:
- it consists only of a single javascript file, so it does not trigger additional requests with rails
- it automagically provides user feedback by selecting the text it has copied
- it provides callbacks for success and error which make it easier to add custom behaviour after copying to the clipboar...
How to monitor Sidekiq: A working example
In order to have monitoring for Sidekiq (like queue sizes, last run of Sidekiq) your application should have a monitoring route which returns a json looking like this:
{
"sidekiq": {
"totals": {
"failed": 343938,
"processed": 117649167
},
"recent_history": {
"failed": {
"2016-11-06": 1,
"2016-11-07": 46,
"2016-11-08": 0,
"2016-11-09": 0,
"2016-11-10": 0
},
"processed": {
"2016-11-06": 230653,
"2016-11-07": 230701,
"2016-11-08"...
tesseract.js: Pure Javascript OCR for 62 Languages
This might be relevant for us since we're often managing customer documents in our apps.
I played around with the library and this is what I found:
- A 200 DPI scan of an English letter (500 KB JPEG) was processed in ~6 seconds on my desktop PC. It does the heavy lifting in a Web worker so you're rendering thread isn't blocked.
- It detected maybe 95% of the text flawlessly. It has difficulties with underlined text or tight table borders.
- When you feed ...
Configure how VCR matches requests to recorded cassettes
VCR lets you configure how it matches requests to recorded cassettes:
In order to properly replay previously recorded requests, VCR must match new
HTTP requests to a previously recorded one. By default, it matches on HTTP
method and URI, since that is usually deterministic and fully identifies the
resource and action for typical RESTful APIs.You can customize how VCR matches requests using the `:match_requests_on casse...
Debugging flickering VCR tests
We often use VCR to stub external APIs. Unfortunately VCR can have problems matching requests to recorded cassettes, and these issues are often hard to debug.
VCR's error messages mostly look like this and are not very helpful:
An HTTP request has been made that VCR does not know how to handle:
POST http://another-site.de:9605/json/index
VCR fails if the request does not exactly look like the request it has recorded. If the request is d...
Styling SVGs with CSS only works in certain conditions
SVG is an acronym for "scalable vector graphics". SVGs should be used whenever an image can be described with vector instructions like "draw a line there" or "fill that space" (they're not suited for photographs and the like). Benefits are the MUCH smaller file size and the crisp and sharp rendering at any scale.
It's a simple, old concept brought to the web – half-heartedly. While actually all browsers pretend to support SVG, some barely complex use cases get you beyond common browser support.
In the bas...
Master the chrome history and autocomplete
1. Sometimes you have search entries in the autocomplete of the address bar, which are higher weighted than your bookmarks. Pressing SHIFT
+ DEL
while searching removes them from the history immediately.
2. Sometimes you have search entries in the autocomplete of the address bar, which are all higher weighted than your recently visited sites. Add a search for your history, so you can get recent results first.
...
VCR fails if the same request is triggered multiple times
Same requests are recorded only once in vcr. Replaying a test fails, if you trigger the same request multiple times. The error message is somehow confusing, as your cassette contains the request:
An HTTP request has been made that VCR does not know how to handle
If you want to allow to match a request multiple times, you need to configure this explicit with allow_playback_repeats: true. Some exa...
Javascript: Read params from url
There is no build in functionally in jQuery and Prototype to extract params from a url.
-
You can use this library (not tested): jquery-deparam
-
Use Unpoly and the following code snippet
Git: how to work with submodules
Sometimes you might need to nest a git-project inside another git-project. The right strategy is to use submodules in this case.
How git submodules work
- Each submodule is a own git repository
- Once you commit changes in a submodule, the parent repository can link the new
sha
as its reference - You need to take care manually that your git submodules are up-to-date and changes in the submodules are linked in the parent repository
Add a submodule
Here is how you add a nested project inside your parent project
$ git submodule...
An intro to Javascript promises
Promises are the new way™ to express "Do this, and once you're done, do that". In contrast to callbacks, promises are easily chainable. From the readme of Q
, an early implementer of the pattern:
The callback approach is called an “inversion of control”. A function that accepts a callback instead of a return value is saying, “Don’t call me, I’ll call you.”. Promises un-invert the inversion, cleanly separating the input arguments from control flow arguments. This simplifies the use and creation of APIs, p...
Amazon S3: Give a user write-access to selected buckets
There's no user interface to give an AWS IAM user read/write access to a selected list of S3 buckets.
Instead you need to attach an IAM policy like the one below to the user:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::bucket1",
"arn:aws:s3:::bucket2"
]
},
{
"Effect": "Allow",
"Action": [
...
Ruby: __FILE__, __dir__ and symlinks
Ruby's __FILE__
keyword returns the path to the current file. On popular for this are Ruby binaries:
#!/usr/bin/env ruby
$LOAD_PATH << File.expand_path('../../lib', __FILE__)
require 'my_cli'
MyCli.run!
However, if you create a symlink to this file, this will no longer work. __FILE__
will resolve to the path of the symlink, not to its target.
One solution is to use File.realpath(__FILE__)
.
In Ruby 2+ you can also use this:
$LOAD_PATH << File.expand_path('../lib', __dir__)
__dir__
is simply a shortcut for `...
Middleman does not fingerprint asset paths by default
We're using Middleman for some static sites like our blog.
Despite being very similar to Rails, Middleman does not add a fingerprint hash to its asset paths by default. This means that when you write this:
<%= javascript_include_tag 'all.js' %>
... you always get the same path, regardless of the contents of all.js
:
<script src='/javascripts/all.js'>
Because browsers tend to cache assets for a while, this means that users might not get your changes until their cac...
How to find out what is running on a port on a remote machine
By convention, common protocols use a defined port, like 80 for HTTP or 443 for HTTPS.
You can use nmap
to find out what service is running behind a given port, and most often see some details about it. This can be helpful if servers don't offer the services you expect for some ports. If you'd like to see what ports are listing on your local machine, you might want to use netstat
instead of nmap
.
Note that nmap's service discovery may trigger several requests.
Example
When using nmap, adding the -A
switch ...
Building web applications: Beyond the happy path
When building a web application, one is tempted to claim it "done" too early. Make sure you check this list.
Different screen sizes and browsers
Desktops, tablets and mobile devices have all different screen resolutions. Does your design work on each of them?
- Choose which browsers to support. Make sure the page looks OK, is usable and working in these browsers.
- Use @media queries to build a responsive design
- If you do not suppo...
Using Google Analytics with Unpoly
The default Google Analytics might not work as expected with your Unpoly app. This is because your app only has a single page load when the user begins her session. After that only fragments are updated and the <script>
tag that sends the page view to Google Analytics is probably never evaluated again.
Luckily you can fix this.
Simple mode: You just want to track all the page views
Embed your Google Analytics code as always.
Now add the following code snippet:...