Waiting for page loads and AJAX requests to finish with Capybara
If you're using the Capybara webdriver, steps sometimes fail because the browser hasn't finished loading the next page yet, or it still has a pending AJAX request. You'll often see workarounds like
When I wait for the page to load
Then ...
Workarounds like this do not work reliably, will result in flickering tests and should be avoided. There is no known reliable way to detect if the browser has finished loading the page.
Solution
Instead you should wait until you can observe the result of a page load. E.g. if y...
Ruby: Extract the hostname from a URL
url = 'http://www.foocorp.com/foo/bar'
URI.parse(url).host
# => www.foocorp.com
Note that this will raise an error if the given argument is not a URL.
If you need the host's full URL without path, query, fragment etc., use URI.join
with a clever twist:
url = 'http://www.foocorp.com:33546/foo/bar?query=foobar#hash'
URI.join url, '/'
# => http://www.foocorp.com:33546/
Manually requiring your application's models will lead to trouble
In a nutshell:
If you require your Rails models manually, pay attention to the path you use. Unless you have to, don't do it at all.
Background
Consider these classes:
# app/models/user.rb
class User < ActiveRecord::Base
validate :magic
def magic
errors.add_to_base('failed') if bad_things?
end
end
^
# app/models/foo.rb
require 'user'
class Foo
# something happens here
end
Now, when your environment is booted, Rails will automatically load your models, like User
...
CSS-Style
Richard Powell presents a collection of CSS styling advice that's mainly taken from SMACSS. Although at makandra we're using BEM instead of SMACSS, here's my favorites.
Do not use ID's in CSS Selectors
It is never safe to assume there will only ever be one of something on a page so do not use ID's for CSS. Id's are much better used as javascript hooks so use them for this instead.
.list {…} instead of #list {…}
Animate an interface using classes not inline styles
Inline styles added by javascript are h...
Howto transfer a single mysql table between several deployment stages
Example task: Multiply the table holidays
between several stages.
-
Open two terminals:
shell-for stage_1 shell-for stage_2
-
Get the stage1 and stage2 MySQL credentials:
cat /opt/www/the_stage.host.tld/current/config/database.yml cat config/database.yml # should do it
-
Dump the table to a path reachable by the stage2 user (e.g. home):
mysqldump -h mysql1 -u stage_1_user -p stage_1_database table_name > ~/table_name_dump.mysql # Select certain records using --where "some_id > 666"
(-...
Paperclip: undefined method `to_file' for #<Paperclip::Attachment:0000> (NoMethodError)
to_file
has been removed in Paperclip 3.0.1.
Instead of using File
to access Paperclip storage objects (like this: File.read(file.to_file.path)
) you can use
Paperclip.io_adapters.for(file).read
Git basics: checkout vs. reset
Today I got a better understanding of how git works, in particular what git checkout
and git reset
do.
Git basics
- A commit holds a certain state of a directory and a pointer to its antecedent commit.
- A commit is identified by a so-called ref looking something like
7153617ff70e716e229a823cdd205ebb13fa314d
. - HEAD is a pointer that is always pointing at the commit you are currently working on. Usually, it is pointing to a branch which is pointing to that commit.
- Branches are nothing but pointers to commits. Y...
Distribute files from a private bucket on AWS S3
Given you store files on Amazon S3 and you need to stream those files out to people while you don't want them to be able to distribute the content simply by sharing the S3 URL.
You could either mark the bucket as private and fetch the appropriate files from S3 to your application server and stream them to the client finally. While this is possible, I'd recommend to use what AWS calls "Query String Authentication".
If you're using Paperclip you can chose between two sto...
Create autocompletion dropdown for Cucumber paths in Textmate
Ever wanted autocompletion for paths from paths.rb
in Cucumber? This card lets you write your steps like this:
When I go to path *press tab now* # path is replaced with a list of all known Cucumber paths
This is how you do it
(key shortcuts apply for TextMate2)
-
Open the bundle editor (ctrl + alt + + B)
-
Create a new Item ( + N), select "Command"
-
Paste this:
^
#!/usr/bin/env ruby -wKU
require File.join(ENV['TM_SUPPORT_PATH'], 'lib', 'ui.rb')cucumber_paths = File.join ENV['TM_PROJECT_DIRECTORY'], 'features'...
Highlight current navigation item with Staticmatic
StaticMatic is a nice tool to build simple static websites.
In case you want to have some nifty styles on the navigation item that is currently active, you can use this:
=link 'Aktuelles', :class => (current_page =~ /aktuelles/) ? 'current' : 'default'
Keep in mind that current_page
gives you the full relative path of your page. raise
current_path in case you're not sure.
I know there is an navigation helper out there. I did not use it and also did not want to migrate.
How to make your application assets cachable in Rails
Note: Modern Rails has two build pipelines, the asset pipeline (or "Sprockets") and Webpacker. The principles below apply for both, but the examples shown are for Sprockets.
Every page in your application uses many assets, such as images, javascripts and stylesheets. Without your intervention, the browser will request these assets again and again on every request. There is no magic in Rails that gives you automatic caching for assets. In fact, if you haven't been paying attention to this, your application is probabl...
Fix error: Invalid gemspec / Illformed requirement
When you get an error like this:
Invalid gemspec in [/opt/www/foo-project.makandra.de/shared/bundle/ruby/1.8/specifications/carrierwave-0.6.2.gemspec]: Illformed requirement ["#<YAML::Syck::DefaultKey:0x7fda6f84d2e8> 1.1.4"]
... the machine's Rubygems needs to be updated.
If that happens on your local machine
- Manually remove the offending's gem files and specifications. The paths will be something like
/usr/lib/ruby/gems/1.8/gems/your-broken-gem
and `/usr/lib/ruby/gems/1.8/specificatio...
Paperclip: Move attachements from local storage to AWS S3
We frequently use the handy Paperclip Gem to manage file attachments.
If you need to move the files from local storage (i.e., your servers' harddisk) to Amazon S3, you can simply change settings for Paperclip to use the S3 storage adapter and use this script to migrate to S3. Put the snippet into a chore if you don't want to run that in the console.
YOUR_LOCAL_STORAGE_MODEL_DIRECTORY should be something like 'storage/your_model'.
Dir.glob(YOUR_LOCAL_STORAGE_MODEL_DIRECTORY**/*).each do |path|...
How to deal with strange errors from WEBrick
If you get errors from your development WEBrick that contain unicode salad, you are probably requesting the page via SSL. \
Since WEBrick does not speak SSL, so change the URL in your browser to use http
instead of https
.
The error looked like this for me:
[2012-09-06 11:19:07] ERROR bad URI `\000\026\000\020\000'.
[2012-09-06 11:19:07] ERROR bad URI `\000\026\000\020\000'.
[2012-09-06 11:19:07] ERROR bad Request-Line `\026\003\001\000�\001\000\000\177\003\001PHj�\031\006�L��'.
[2012-09-06 11:19:07] ERROR bad URI `\000\026\000\...
How to test print stylesheets with Cucumber and Capybara
A print stylesheet is easy to create. Choose a font suited for paper, hide some elements, done. Unfortunately print stylesheets often break as the application is developed further, because they are quickly forgotten and nobody bothers to check if their change breaks the print stylesheet.
This card describes how to write a simple Cucumber feature that tests some aspects of a print stylesheets. This way, the requirement of having a print stylesheet is manifested in your tests and cannot be inadvertedly removed from the code. Note that you can...
Ruby tempfiles
Tempfiles get deleted automatically
With the the ruby Tempfile class you can create temporary files. Those files only stick around as long as you have a reference to those. If no more variable points to them, the GC may finalize the object at some point and the file will be removed from the filesystem. If you would try to access your tempfile then using its path (which you stored previously), you would get an error because the file no longer exists.
Unlink your tempfiles when you're done with them
-...
Git: When committing, check the diff
When committing, you should always check the diff of your changes so you don't include any leftovers or irrelevant/bad changes. Any time spent on that is well invested as it saves you rejected merge requests or any mess you need to clean up later.
While you can just use git diff
or git diff --cached
(to diff staged changes), you can also have Git include the changes as a comment below the commit message:
git commit -v
That will open up the usual commit "file" in your preferred text editor, but it will include a diff below the s...
Impressumspflicht bei Facebook & Twitter: Schnelle Info und Abhilfe
Jedes nicht rein private Profil auf Social Media Portalen muss ein Impressum haben, das heißt insbesondere Unternehmen und Freiberufler (§ 5 Abs.1 TMG). Wer das Impressum dort nicht unter einem eigene Button mit der Aufschrift “Impressum” oder “Kontakt” unterbringt, bietet eine große Angriffsfläche für Abmahner (Quelle: http://rechtsanwalt-schwenke.de/impressumspflicht-bei-google-plus-und-twitter/).
Hier also in kurzen Schritten, wie man ein Impressum erstellt und wie man es bei Facebook und Twitter einbindet:
#1. Impressum erstellen
Ic...
Understanding the Selenium error "Modal Dialog Present" (aka Selenium::WebDriver::Error::UnhandledAlertError)
So your Cucumber feature sometimes dies with this exception:
Modal Dialog Present (Selenium::WebDriver::Error::UnhandledAlertError)
As a seasoned Selenium veteran you are used to misleading error messages. Hence you might be surprised that the reason for this particular error is that there is actually a modal dialog present and preventing Selenium from executing commands like click
or page.have_css?
.
How your code triggers this issue
The reason why a dialog is shown is somewhat fucked ...
Test your CSS rendering output with GreenOnion
No one wants to cry over regression issues in views; does testing HTML and CSS have to be such a back and forth between designers and devs? Why is it that the rest of the stack can have TDD and BDD but not the presentation layer? Well, GreenOnion is here to help you get the same results on testing front-end styling that you've enjoyed in your unit and integration tests up to now.
GreenOnion records 'skins', which are snapshots of the current state of a view (or any page that a browser can navigate to). The first time that it is run on a view...
Don't follow Ajax requests with a redirect
The behaviour of browsers is very inconsistent when an Ajax request is answered with a redirect. Highlights are:
- IE 9 will follow a DELETE request with a second DELETE. You never want that.
- Firefox will follow a POST request with a GET, as you might expect. If a PUT is redirected however, you will get a confirmation dialog, where you can choose to follow with a second PUT or simply abort. You don't want that either.
Request limit of graph.facebook.com
The facebook API allows up to 600 requests per 600 seconds.
If you poll more often, you'll get no or malformed answers.
Capistrano: How to find out which version of your application is currently live
When deploying, Capistrano puts a REVISION
file into your application's release directory. It contains the hash of the commit which was deployed.
If you want to know the currently deployed release, simply SSH to a server and view that file.
$ cat /var/www/my-project/current/REVISION
cf8734ece3938fc67262ad5e0d4336f820689307
Capistrano task
When your application is deployed to multiple servers, you probably want to see a result for all of them.
Here is a Capistrano task that checks all servers with the :app
role.
Bundler: Fatal error and 'no such file to load -- net/https'
Today, I ran into trouble on a fairly fresh installed VM, running Ubuntu. I tried to bundle install
and got this stacktrace:
Fetching gem metadata from https://rubygems.org/.Unfortunately, a fatal error has occurred. Please see the Bundler
troubleshooting documentation at http://bit.ly/bundler-issues. Thanks!
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require': no such file to load -- net/https (LoadError)
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
from /usr/li...