Autofocus a form field with HTML5 or jQuery

In Webkit you can use the HTML5-attribute autofocus:

= form.text_field :title, :autofocus => 'autofocus'

Here is a jQuery fallback for browsers that don't speak HTML5:

var Autofocus = {

  supported: function() {
    return 'autofocus' in document.createElement('input');
  },

  fake: function() {
    $('[autofocus]').focus();
  },

  extend: function() {
    Autofocus.supported() || Autofocus.fake();
  }

};

$(Autofocus.extend);

Fixing Webrat after following an external link

When a Cucumber feature leaves your page through an external Link, Webrat has problems like "Could not find field: "E-mail" (Webrat::NotFoundError)" using your page afterwards. It will also have trouble following redirects.

Fix it with this step:

Given /^I am back on my page$/ do
  webrat_session.header("Host", "www.example.com")
end

MySQL replication how-to

This may be awkward to set up, but will work once you're done.

Fun facts:

  • In case of a connection loss the slave will try to reconnect to the master server and resume replication for the next 24 hours
  • If you want to use your slave as a "real" MySQL server, you basically need to switch off replication (STOP SLAVE; RESET SLAVE; and reset your my.cnf) and restart the MySQL daemon.

Master server configuration

  • Create replication user
    : In the MySQL shell:

      CREATE USER 'replicator'@'%' IDENTI...
    

MySQL Server and UTF-8 Defaults

Unless all MySQL server defaults are set to UTF-8, mysqldump encodes UTF-8 characters incorrectly and only outputs correct UTF-8 when you switch to Latin 1 (!). Also you need to setup charset and collation manually for each new database.

To prevent this, make sure your /etc/mysql/my.cnf looks like this:

[mysqld]
default-character-set = utf8mb4
collation-server = utf8mb4_unicode_ci

[mysql]
default-character-set=utf8mb4

After that do

sudo /etc/init.d/mysql restart

Convert a Subversion repository to Git

  • To retain all branches you can try the svn2git tool. However, this tool has some bugs.
  • To only import the trunk (with complete history): git svn clone http://host/svn/...
  • Create a .gitignore after the conversion.
  • Turn the folder into a git repository as described here.

Branching and merging in Subversion

  • Create a branch: svn copy https://dev.makandra.de/svn/filepanic/trunk https://dev.makandra.de/svn/filepanic/branches/$ticketnumber_shortdesc
  • Don't just copy the folder into your working copy and try a commit without a merge because Subversion will die on you.
  • Work on ./branches/$ticketnumber_shortdesc.
  • If you work on a long story it is useful to sometimes merge the trunk into your branch so there will be less pain later: svn merge https://dev.makandra.de/svn/filepanic/trunk ./branches/$ticketnumber_shortdesc.
  • When you're done...

Common Screen Resolutions

Optimize for

  • Notebook: 1280x800 (many consumer notebooks)
  • Netbook: 1024x600
  • Desktop: 1440x900 / 1680x1050 (19"- und 22"-Widescreen-TFTs)
  • iPad: 768x1024

Notebooks

  • 1280x800 (13.3"-15.4", 16:10)
  • 1440x900 (15.4", 16:10)
  • 1680x1050 (15.4"+, 16:10)
  • older notebooks cf. Desktops (1024, 1280, ...)

Desktops

  • 1440x900 (19", 16:10)
  • 1680x1050 (22", 16:10)
  • 1920x1080 (23", 16:9)
  • 1920x1200 (24", 16:10)
  • 1024x768 (17", 4:3)
  • 1280x1024 (19", 5:4)
  • 1600x1200 (21", 4:3)

Netbooks

  • 720x480 (7")
  • 1024x600 (8.9")

...

Load all models into an Array

Dir.glob(File.join RAILS_ROOT, 'app', 'models', '*.rb').collect{ |path| path[/.+\/(.+).rb/,1] }.collect(&:camelize).collect(&:constantize)

Cucumber Webrat steps

Most of these will not work in newer projects because these use the Capybara/Rack::Test combo in lieu of Webrat.

Find input fields

Then /^there should be a "([^"]+)" field$/ do |name|
  lambda { webrat.current_scope.send(:locate_field, name) }.should_not raise_error(Webrat::NotFoundError)
end

Then /^there should be no "([^"]+)" field$/ do |name|
  lambda { webrat.current_scope.send(:locate_field, name) }.should raise_error(Webrat::NotFoundError)
end

Find html content

Then /^I should see "([^\"]*)...

Reprocess only missing images with Paperclip

When a paperclip attachment gains a new style and you have many attachments, reprocessing can take ages. This is because all styles are being recomputed.

To create only missing images, patch Paperclip like this in your script that does the reprocessing:

Paperclip <2.3.2

class Paperclip::Attachment
  private

  def post_process_styles_with_extreme_lazyness
    @old_styles = @styles

    @styles = @styles.reject do |name, _|
      exists?(name)
    end

    post_process_styles_without_extreme_...

Convert colorspace of images attached with Paperclip

has_attached_file(
  :avatar,
  :styles => { :large => "300x300", :small => "100x100" },
  :convert_options => { all => "-colorspace RGB" }
)

Reprocess Paperclip attachments in one line

script/runner -e development 'Article.all.each { |a| a.image.reprocess! if a.image.exists? }; "done"'

Release gem; Deploy gem; Update a gem created with Jeweler

Until May 2011 our gems have been created with Jeweler, which is a helper library to package code into a gem. You know a gem was cut with Jeweler if you see the word jeweler in a gem project's Rakefile.

This note describes how to update a gem that was cut using Jeweler. Note that this can be traumatic the first time. It would be great to have an easier workflow for this. Jeweler is deprecated these days because you can

**now [cut gems more easily using Bundler](https://makandracards.com/makandra/1229-updat...

Aggregated RSpec/Cucumber test coverage with RCov

With defaults, RCov doesn't work the way you how you would like it to. To create a nice test coverage report, copy the attached file to lib/tasks/rcov.rake. After that rake rcov:all will run all RSpec examples and Cucumber features. The report will be written RAILS_ROOT/coverage/index.html.

Here is what the task does in detail:

  • Generates aggregated coverage of both RSpec and Cucumber
  • Works with Rails 2 and Rails 3
  • Reports for app/**/*.rb and nothing else
  • If called with an environment variable IGNORE_SHARED_TRAITS=true it ...

Test concurrent Ruby code

To test concurrent code, you will need to run multiple threads. Unfortunately, when you use blocking system calls (e.g. locks on the database), Ruby 1.8 threads won't work because system calls will block the whole interpreter.

Luckily you can use processes instead. fork spins off a new process, IO.pipe sends messages between processes, Process.exit! kills the current process. You will need to take care of ActiveRecord database connections.

Here is a full-fledged example:

describe Lock, '.acquire' do

  before :each do
  ...

Better Output for RSpec

rspec_spinner is a progress bar for RSpec which outputs failing examples as they happen (instead of all at the end).

Installation

gem install rspec_spinner

Usage

script/spec -r rspec_spinner -f RspecSpinner::Bar -c

To make a shortcut in your .bashrc

alias ss='script/spec -r rspec_spinner -f RspecSpinner::Bar -c'

There's also an alternate runner RSpecSpinner::Spinner which shows a spinner and the name of the current spec instead of a progress bar.

Array.uniq does not work in Prototype

For arrays of objects, uniq does not work as expected, since it uses strict equality. So

[[1], [1]].uniq() == [[1], [1]]

In some cases, this might be a workaround:

[[1], [1]].invoke("toJSON").uniq().invoke("evalJSON")   
// == [[1]]

Concurrent Tests

Install gem and plugin

sudo gem install parallel
script/plugin install git://github.com/grosser/parallel_tests.git

Adapt config/database.yml

test:
  database: xxx_test<%= ENV['TEST_ENV_NUMBER'] %>

Create test databases

script/dbconsole -p
CREATE DATABASE `xxx_test2`;
...

Generate RSpec files

script/generate rspec

(you'll probably only let it overwrite files in script/)

Prepare test databases...

Parse XML or HTML with Nokogiri

To parse XML-documents, I recommend the gem nokogiri.

A few hints:

  • xml = Nokogiri::XML("<list><item>foo</item><item>bar</item></list>") parses an xml string. You can also call Nokogiri::HTML to be more liberal about accepting invalid XML.
  • xml / 'list item' returns all matching nodes; list item is used like a CSS selector
  • xml / './/list/item' also returns all matching nodes, but .//list/item is now an XPath selector
    • XPath seems to be triggered by a leading ....

Rails - Multi Language with Fast_Gettext

  • sudo gem install gettext --no-ri --no-rdoc
  • sudo gem install fast_gettext --no-ri --no-rdoc
  • script/plugin install git://github.com/grosser/gettext_i18n_rails.git (didn't work as gem)
  • environment.rb: see code example at the bottom
  • if this is your first translation: cp locale/app.pot locale/de/app.po for every locale you want to use
  • use method "_" like _('text') in your rails code
  • run rake gettext:find to let GetText find all translations used
  • translate messages in 'locale/de/app.po' (leave msgstr blank and ms...

Automatically build sprites with Lemonade

How it works

See the lemonade descriptions.

Unfortunately, the gem has a few problems:

  • it does not work with Sass2
  • it always generates all sprites when the sass file changes, which is too slow for big projects
  • it expects a folder structure quite different to our usual

All these problems are solved for us, in our own lemonade fork. This fork has since been merged to the original gem, maybe we can use t...

Using Passenger for development (with optional SSL)

  • install apache
  • sudo apt-get install ruby1.8-dev
  • sudo gem install passenger
  • sudo passenger-install-apache2-module
  • follow the instructions

Manually: configure a vhost in /etc/apache2/sites-available and link it to /etc/apache2/sites-enabled with something like the following
^
NameVirtualHost *:80

<VirtualHost *:80>
        ServerName application.local
        DocumentRoot /opt/application/public
        RailsEnv development
        RailsAllowModRewrite off
</VirtualHost>

<VirtualH...