It's OK to put block elements inside an <a> tag
In general, you should not put a block element inside an inline element. So don't do this:
<span>
<div>text</div>
</span>
The browser will think you wrote invalid HTML by accident, and will sometimes reorder elements silently.
There is one notable exception: It's OK to wrap block elements in a <a> tag in HTML5 (not 4). The spec says:
The a element may be wrapped around entire paragraphs, lists, tables, and so forth, even entire sections, so long ...
Take care of indentation and blank lines when using .erb for plain text emails
Building plain text emails with an .erb template doesn't allow you to indent code like you normally do in HTML mails.
❌ DON'T
<%= 'foo' if bar %>
"\n" if bar is false
"foo\n" if bar is true
<%= nil %>
"\n"
<% if true %>
<%= 'foo' %>
<% end %>
" foo"
<%= 'foo' %>
<%= 'bar' %>
"foo\n\nbar\n"
✔️ DO
Write unindented code to get the expected result.
<% if bar %>
<%= 'bar' %>
<% end %>
<%= 'foo' %>
<%= 'bar' %>
- Use [Form Models](https://github.com/makandr...
Summarizing heredoc in Ruby and Rails
This card tries to summarize by example the different uses of heredoc.
- In Ruby
<<vs.<<-vs.<<~ - In Rails
strip_heredocvs.squish
strip_heredoc should be used for a text, where you want to preserve newlines. (multi-line -> multi-line)
squish should be used for a text, where you want to squish newlines. (multi-line -> one-line)
Ruby 2.3+
def foo
bar = <<~TEXT
line1
line2
line3
TEXT
puts bar.inspect
end
foo => "line1\nline2\nline3\n"
Read more: [Unindent HEREDOCs in Ruby 2.3](/m...
Debugging cucumber feature with javascript + firefox vnc
TL;DR Debugging problems with javascript errors in cucumber tests is sometimes easier in the browser. Run the test, stop at the problematic point (with Then pause from Spreewald 1.7+) and open VNC for Firefox.
Features:
- It does not freeze your server like when you're using a debugger. (Compared to the
Then consolestep) - It enables interacting with the server. (Compared to taking screenshots in Capybara)
- It is a faster alternat...
Giving a presentation with a dual screen layout on linux
When giving a presentation with a projector it is sometimes better to use a dual screen layout instead of a cloned display. If you still want a preview of the projector screen on your primary screen, you can do this:
-
Install
x11vncand a vnc viewer (e.g.xtightvncviewer). -
Connect the projector.
-
In your system display settings, move the projector to the left or your primary screen (not strictly necessary, but I had weird clipping issues otherwise).
-
Start a vnc server for your second display with
x11vnc -clip xinera...
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...
Subclassing module
Yesterday I stumbled across a talk in which the guy mentioned module sub-classing. I was curious what you can do with it and found his blog post with a cool example. It allows you to inject some state into the module you are including elsewhere. Check it out!
class AttributeAccessor < Module
def initialize(name)
@name = name
end
def included(model)
super
define_accessors
end
private
def define_accessors
ivar = "@#{@name}"
define_writer(ivar)
define_reader(ivar)
end
def define_writer(ivar)
...
Angular with haml: Dynamic html classes
A haml angular 1 template with
.thing(class="is-{{:: item.type }}")
will be compiled (by haml) to
<div class="is-{{:: item.type thing }}"></div>
which is not what you want! It will also crash in angular (unless thing is a valid variable in your angular directive) with Error: [$parse:syntax] Syntax Error: Token 'thing' is an unexpected token at column 11 of the expression [item.type thing]
Solution 1: Use ng-class instead of class
.thing(ng-class='"is-{{ item.type }}"')
**Solution 2: Don't let haml b...
Developer Soft Skills
Knowing when to refactor
Just feeling like refactoring is not a good reason to do it. Make an educated decision: Is the code change worth the effort? Stay straight on track, don't go astray.
Note: Usually, you'd refactor after finishing your story. At times, it might be necessary to refactor up front. But try to keep refactoring out of your current task.
Knowing where to optimize
Things should only be optimized a) when they have settled, i.e. haven't changed for a longer time, and b) when there is a measurable gain from th...
How to "git diff" with a graphical diff tool
If you are fine with the default console diff most of the time but only sometimes want to use an external tool for viewing a diff, you can use git difftool.
E.g. viewing git diff with meld:
git difftool --tool=meld
For each file in the diff you will be asked if you want to view it using meld.
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...
Running awstats on a single logfile
AWstats is build to regularly run on webservers. If you want it to build a report once, here is the minimal configuration you need:
Put the following into the awstats config file (look into /etc/awstats/awstats.conf.local or look into /etc/awstats/awstats.conf how to do it on your system):
SiteDomain="yourdomain.de"
DirData="."
DNSLookup=0
Run the following to build a simple HTML page:
awstats -staticlinks -config="yourdomain.de" -LogFile=your-logfile.log -output > report.html
This might take a second (it will take ...
makandra/gemika: Helpers for testing Ruby gems
We have released a new library Gemika to help test a gem against multiple versions of Ruby, gem dependencies and database types.
Here's what Gemika can give your test's development setup (all features are opt-in):
- Test one codebase against multiple sets of gem dependency sets (e.g. Rails 4.2, Rails 5.0).
- Test one codebase against multiple Ruby versions (e.g. Ruby 2.1.8, Ruby 2.3.1).
- Test one codebase against multiple database types (currently MySQL or PostgreSQL).
- Compute a matrix of all possib...
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...
How to use Haml in your helpers
You know those helper methods that just render some HTML but look weird because of content_tags all over the place? You could also use Haml instead.
Example
Consider the following helper.
def greeting
message = ''.html_safe
message << 'Welcome to '
message << content_tag(:span, Rails.env, class: 'greeting--location')
content_tag :div, message, class: 'greeting'
end
That looks clumsy and is hard to read.
Wouldn't it be nicer to say something like this?
def greeting
render_haml <<-HAML
...
Minidusen: Low-tech record filtering with LIKE queries
We have a new gem Minidusen which extracts Dusen's query parsing and LIKE query functionality.
Minidusen can no longer index text in MySQL FULLTEXT columns, which was hardly used and didn't always help performance due to the cost of reindexing.
Minidusen is currently compatible with MySQL, PostgreSQL, Rails 3.2, Rails 4.2 and Rails 5.0.
Basic Usage
Our example will be a simple address book:
class Contact < ActiveRecord::Base
validates_presence_of :name, :street, :city, :e...
How to tidy up your Git mess
Git is hard: screwing up is easy, and figuring out how to fix your mistakes is fucking impossible. Git documentation has this chicken and egg problem where you can't search for how to get yourself out of a mess, unless you already know the name of the thing you need to know about in order to fix your problem.
Maybe this flowchart may be of help...
Geordi 1.5.1 released
- Improve
geordi cucumber: Only attempt @solo run when the specified files contain the @solo tag, skip @solo run if any filename is passed with a line number (e.g.features/example.feature:3) - Improve
geordi deploy: Find stages by their prefix (e.g.s-> staging,m-> makandra), bundle if needed, check the selected stage exists - Improve
geordi server: Takes port as argument (e.g.geordi ser 3001), option--public(-P) starts the server with-b 0.0.0.0to make it accessible from other machines in the local network, e.g. ...
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...
Angular directive scope binding with = (equals)
Angular directives with isolate scopes have three different variable binding strategies, of which one is =. Example:
# HTML
<panel value="parent.someFn() && false" twoway="parent.someProperty"></div>
# Coffeescript
@app.directive 'panel', ->
scope:
evaluated: '=value'
bound: '=twoway'
link: ->
scope.evaluated # = false
scope.bound = 'foo' # Updates parent.someProperty
HTML attributes bound with = (value, twoway) have their value evaluated as Angular expression in the parent scope's context and have the ...
Angular isolate scopes: Calling a parent scope function with externally defined arguments
Isolate scopes offer three kinds of variable binding. One of them is &, allowing to bind a property of the isolate scope to a function in the parent scope. Example:
# HTML
<panel proxy="parent.someFunction(arg1, arg2)"></div>
# Coffeescript
@app.directive 'panel', ->
scope:
parentFn: '&proxy'
link: (scope) ->
scope.parentFn(arg1: 'first', arg2: 'second')
In this dumb example, the panel directive will call its scope's parentFn() function with two arguments, which proxies to parent.someFunction('first', 'second')...
Your browser might silently change setTimeout(f, 0) to setTimeout(f, 4)
When you're nesting setTimeout(f, 0) calls, your browser will silently increase the delay to 5 milliseconds after the fourth level of nesting.
This is called "timeout clamping" and defined in the HTML spec:
If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.
Timeouts are clamped harder in background tabs
On a similar note, all major browsers have implemented throttling rules for setInterval and setTimeout calls from tabs...
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...
Represent astral Unicode characters in Javascript, HTML or Ruby
Here is a symbol of an eight note: ♪
Its two-byte hex representation is 0x266A.
This card describes how to create a string with this symbol in various languages.
All languages
Since our tool chain (editors, languages, databases, browsers) is UTF-8 aware (or at least doesn't mangle bytes), you can usually get away with just pasting the symbol verbatim:
note = '♪'
This is great for shapes that are easily recognized by your fellow programmers.
It's not...