Don't forget: Automatically remove join records on has_many :through associations
Bad
# Given the following models
class Image < ActiveRecord::Base
has_many :album_images
has_many :albums, through: :album_images
end
class Album < ActiveRecord::Base
has_many :album_images
has_many :images, through: :album_images
end
# Join model
class AlbumImage < ActiveRecord::Base
belongs_to :album
belongs_to :image
end
Destroying a record in this setup will only remove the record itself, and leave orphaned join records behind.
image = Image.last
image.destroy # removes only the `image` record,
...
Using form models (aka decorators) with Devise
To use a form model with devise, you can simply override #resource_class
in a controller. A typical use case would be the registrations controller, as users will need some fields only on sign-up. Example:
class Frontend::Authentication::RegistrationsController < Devise::RegistrationsController
private
def resource_class
FrontendUser::AsSignUp # my decorator class, extending from FrontendUser
end
end
Fontawesome 4+ icon naming conventions
Fontawesome 4 has introduced new naming conventions that make it easy to retrieve variants of a given icon.
The format is:
fa-[name]-[alt]-[shape]-[o]-[direction]
Note that this is a naming convention which doesn't imply there's an icon for any combination of tags.
name
The name of the icon, e.g. comment
, print
, bookmark
etc. See the full list.
alt
An alternative icon.
shape
The icon inside a circle
or square
.
o
An outlined ...
Rails 4 introduced collection_check_boxes
Starting from Rails 4.0, you can use a special form options helper called #collection_check_boxes
. It behaves similar to #collection_select
, but instead of a single select field it renders a checkbox and a label for each item in the collection.
= form_for @post do |form|
= form.collection_check_boxes :author_ids, Author.all, :id, :name_with_initial
How generated form params look like
---------------------------------...
Capybara: Waiting for pending AJAX requests after a test
When ending a Selenium test Capybara resets the browser state by closing the tab, clearing cookies, localStorage
, etc.
It may be a good idea to wait for all in-flight AJAX requests to finish before ending a scenario:
- You may have client-side JavaScript that freaks out when the tab closure kills their pending requests. If that JavaScript opens an error alert or spams errors to the console, your test may fail after the last step.
- With unlucky timing the server may receive an AJAX request as the browser tab closes, causing a connection ...
rspec_candy 0.4.0 released
- Now supports RSpec 3 and Rails 4
- Drops support for
state_machine
, which has some issues with Rails 4 and isn't actively maintained
Differences between transactions and locking
Web applications can be used by multiple users at the same time. A typical application server like Passenger has multiple worker processes for a single app. In a distributed deployment setup like we use at makandra you will even have multiple application servers, each with their own worker pool.
This means that your code needs to deal with concurrent data access. The two main tools we use to cope with concurrency are database transactions and distributed locks. These two are not interchangeable. You ca...
Verifying doubles in RSpec 3
RSpec 3 has verifying doubles. This breed of mock objects check that any methods being stubbed are present on an instance of a given class. They also check methods aren't called with the wrong number of arguments.
This dual approach allows you to move very quickly and test components in isolation, while
giving you confidence that your doubles are not a complete fiction.
You should always prefer using a verifying double to using an old-school mock
...
Communication between collaborating directives in Angular
What if a complicated component comes along that is naturally modeled by multiple directives? This group of directives, as a whole, form a single self contained component. None of directives in the group can stand alone because they only make sense when used together; they collaborate; they are aware of each other and need to communicate with each other.
This post will discuss best practices for managing communication among collaborating directives and illustrate these practices with an example.
Versatile Cucumber step regarding hovering above elements
Here's a pretty useful steps that hasn't made it into Spreewald yet.
It is best used with the auto-mapper for BEM classes in features/support/selectors.rb
When I hover above [selector] element
When /^I hover above (.*) element$/ do |selector|
page.find(selector_for(selector)).hover
end
Example:
When I hover above the album's image element
→ triggers a hover event on .album--image
Slack integration for deployments via Capistrano
You can hook into Slack when using Capistrano for deployment. The slackistrano gem does most of the heavy lifting for you. Its default messages are unobtrusive and can be adjusted easily.
When deploying, it posts to a Slack channel like this:
How to integrate
Integrating Slackistrano with Capistrano 3 is fairly simple.
- In your Slack, open menu → A...
Use CSS sibling selectors instead :last-child (or :first-child)
Often times you want to give a bunch of elements the same style, except for the last. For example borders or margins.
You probably commonly used the :last-child
CSS meta selector like so:
.foo {
border-bottom: 1px dashed #000;
}
.foo:last-child {
border-bottom-width: 0;
}
However, this only works when an element is the last child of its parent. Any other siblings which are unrelated to your case will break it.
Instead, prefer using the +
sibling selector. It applies to the element following the other.
.foo + .foo {
...
Ruby: Removing leading whitespace from HEREDOCs
If you're on Ruby 2.3+ there's a <<~
operator to automatically unindent HEREDOCs:
str = <<~MESSAGE
Hello Universe!
This is me.
Bye!
MESSAGE
If you have an older Ruby, you can use the String#strip_heredoc
method from ActiveSupport. See Summarizing heredoc in ruby and rails for an example.
Technically...
Detecting when fonts are loaded via JavaScript
Webfonts are not always available when your JavaScript runs on first page load. Since fonts may affect element sizes, you may want to know when fonts have been loaded to trigger some kind of recalculation.
Vanilla JavaScript / Modern DOM API
In modern browsers (all but IE and legacy Edge) you can use document.fonts
. Use load
to request a font and receive a Promise that will be resolved once the font is available. Example:
document.fonts.load('1rem "Open S...
Sharing cookies across subdomains with Rails 3
To achieve this goal you have to setup the session store like the following example:
MyApp::Application.config.session_store(
:cookie_store,
{
:key => '_myapp_session',
:domain => :all, # :all defaults to da tld length of 1, '.web' has length of 1
:tld_length => 2 # Top Level Domain (tld) length -> '*.myapp.web' has a length of 2
}
)
The invconvenient side effect for local development
… or: Why do I get "Can't verify CSRF token authenticity" even if csrf token is present?
As `:domain => :all...
How to create giant memory leaks in AngularJS (and other client-side JavaScript)
This guide shows how to create an AngularJS application that consumes more and more memory until, eventually, the browser process crashes on your users.
Although this guide has been written for Angular 1 originally, most of the advice is relevant for all client-side JavaScript code.
How to observe memory consumption
To inspect the amount of memory consumed by your Javascripts in Chrome:
- Open an incognito window
- Open the page you want to inspect
- Press
Shift + ESC
to see a list of Chrome processes...
An auto-mapper for BEM classes in Cucumber selectors
When you are using the #selector_for
helper in Cucumber steps, as e.g. Spreewald does, the following snippet will save you typing. It recognizes a prose BEM-style selector and maps it to the corresponding BEM class.
For a variation on this idea, see An auto-mapper for ARIA labels and BEM classes in Cucumber selectors.
Examples
"the main menu" -> '.main-menu'
"the item box's header" -> '.item-box--header'
Here are some examples of steps (using Spreewald, too):
T...
grosser/rspec-instafail
Gem to show failing specs instantly.
Unlike the --fail-fast
option it doesn't abort abort on the first failure, but keeps running other examples after print out the failure.
I haven't tried it with parallel_tests
.
Block formatting contexts
TL;DR Block formatting contexts establish an isolating container. float
and clear
only apply to elements within such a container.
About
Block formatting contexts (BFCs) are important for the positioning and clearing
of floats. The rules for positioning and clearing of floats apply only to
things within the same block formatting context.
Floats do not affect the layout of things in other block formatting contexts,
and clear
only clears past floats in the same block formatting context.
How to create a new block form...
Understanding z-index: it's about stacking contexts
The CSS property z-index
is not as global as you might think. Actually, it is scoped to a so-called "stacking context". z-indexes only have meaning within their stacking context, while stacking contexts are treated as a single unit in their parent stacking context. This means indices like 99999
should never actually be needed.
Creating a new stacking context
In order to create a stacking context with the least possible side effects, use the isolation
property on an...
Git: How to get a useful diff when renaming files
tldr; Use git diff -M
or git diff --find-renames
when you've moved a few files around.
Usage
$ git diff --help
Options:
-M[<n>], --find-renames[=<n>]
Detect renames. If n is specified, it is a threshold on the similarity index
(i.e. amount of addition/deletions compared to the file’s size). For example,
-M90% means Git should consider a delete/add pair to be a rename if more than
90% of the file hasn’t changed. Without a % sign, the number is to be read as
a fraction, with a decimal point...
How to load an SQL dump from a migration
If you want to load an SQL dump from an ActiveRecord migration, you might find this to be harder than you thought. While you can call ActiveRecord::Base.connection.execute(sql)
to execute arbitrary SQL commands, the MySQL connection is configured to only accept a single statement per query. If you try to feed it multiple statements, it will die with You have an error in your SQL syntax.
You can work around this by opening a second MySQL connection that does accept multiple statements per call.
Below is an example for a migration that l...
RSpec: Only stub a method when a particular argument is passed
To only stub a method call if a given argument is used, but use the default implementation for other arguments:
object.should_receive(:some_method).and_call_original
object.should_receive(:some_method).with('my argument').and_return('other value')
Requires rspec-mocks
2.13+.