Compose a regular expression from other RegExp objects

You can create a Regexp object from existing Regexp objects by using the interpolation syntax you know from strings:

re1 = /x/
re2 = /a#{re1}b/
'aaxbb' =~ re2 # => 1

Note

If your regular expression contains backreferences like \1, they may no longer refer to the correct capture group after concatentation.

Machinist's #make breaks on has_many associations when defining method `empty?`

Observed on Rails 2.3 and machinist 1.0.6

Like the title says, when you define the method empty? like in the following example, you may not longer use collection.make.

class Book

  has_many :pages

  def empty?
    pages.empty?
  end

end

Assuming

b1 = Book.find(1)
b2 = Book.find(2)

instead of expected

b1.pages.make #=> #<Page id: 1, book_id: 1>
b2.pages.make #=> #<Page id: 2, book_id: 2>

you'll get

b1.pages.make #=> #<Page id: 1, book_id: 3>
b2.pages.make #=> #<Page id: 2,...

dbconsole in Rails 3 requires the environment as the first argument

There is a bug in Rails 3's dbconsole script, which makes the following command open a database console for the development environment:

rails dbconsole -p test

You need to write this instead:

rails dbconsole test -p

Invoices: How to properly round and calculate totals

While it might seem trivial to implement an invoice that sums up items and shows net, gross and vat totals, it actually involves a lot of rules and caveats. It is very easy to create invoices where numbers don't add up and a few cents are missing. A missing cent is a big deal for an accountant, so it is important for your invoices to list correct numbers.

Note that this is not legal advice. Also note that while this note has a number of code examples in Ruby and MySQL, the concepts apply to all programming languages and data stores.

When ...

Always show all form errors during development

You've been there: A form cannot be submitted, but you don't see a validation error because the field at fault has no corresponding input field on the form. Because this is usually a bug, you insert debug information listing all errors into the form view. And once the bug is fixed, you forget to take out that debug information.

There is a better way. By copying one of the attached initializers into config/initializers, your forms will always render a small box listing all form errors in the bottom right corner of the screen. This box is n...

Webrat doesn't follow redirect because it considers the url external

Rails doesn't know which host it is running on. For generating links, it strips the hostname off the request URL, which can lead to errors when you have absolute URLs in your Cucumber tests.

If you really need to use absolute URLs somewhere, say in an email you send, either throw away the host when parsing it (e.g. body.scan(/http:\/\/[^\/]+\/([^\s"<]+)/)) or tell Webrat you're back on your site.

Downgrade Firefox 6 to Firefox 5 on Ubuntu

Note that if you plan to downgrade Firefox because your Selenium tests broke after a Firefox upgrade, there is a better way that doesn't involve downgrading. Mozilla has stated that they will no longer provide security patches for any but the most recent versions of Firefox. So running an old Firefox should not be a long-term solution for anything.

If you still want to downgrade your Firefox for other reasons, here is how I downgra...

Prevent your Firefox from auto-updating

Note that if you plan to freeze your Firefox versions because your Selenium tests break whenever Firefox updates, there is a better way that lets you keep an up-to-date Firefox. Mozilla has stated that they will no longer provide security patches for any but the most recent versions of Firefox. So running an old Firefox should not be a long-term solution for anything.

If you still wish to disable the auto-update in Firefox, a poste...

Distance of time in what you like: days, months, years

Sometimes the Rails helper #distance_of_time_in_words is using too much magic.
When you need a time difference in a specific unit, use this method:
^
def distance_of_time_in(unit, from, to)
diff = to - from

  if 1.respond_to? unit
    distance = diff / 1.send(unit)
    distance.abs.round
  else
    raise ArgumentError, "#{unit.inspect} is not supported as unit"
  end
end

distance_of_time_in(:days, Time.now, 1.year.ago)
=> 365

Remove the .abs if you want the mathematical *differ...

List sizes of MySQL databases

Do you wonder which databases are actually taking up how much space but only have one huge ibdata1 in your /var/lib/mysql and the directories inside your mysql data directory don't represent the actual database sizes? This is for you!

Run from a mysql root console:

SELECT table_schema AS "Database name", SUM(data_length + index_length) / 1024 / 1024 AS "Size (MB)" FROM information_schema.TABLES GROUP BY table_schema;

This will get you a result like the following:

+----------------------+--------------+
| Database name    ...

Fix: FreeBSD is not able to connect to the network

This article from the FreeBSD Handbook suggests that editing /etc/rc.conf enables DHCP. Unfortunately, some times this seems not sufficient.

Try a reboot, or start the DHCP client manually with the command

dhclient <network adapter>

You can find a list of network adapters by running ifconfig. Examples are em0 or lo0.

Detect the current Rails environment from JavaScript or CSS

Detecting if a Javascript is running under Selenium WebDriver is super-painful. It's much easier to detect the current Rails environment instead.

You might be better of checking against the name of the current Rails environment. To do this, store the environment name in a data-environment of your <html>. E.g., in your application layout:

<html data-environment=<%= Rails.env %>>

Now you can say in a pi...

How to: Store multiple Vim commands in macros and recall them

Vim allows recording a batch of commands as a macro. This is handy if you need to do the same things over and over.

Here is how:

  1. Press q to enter macro mode.
  2. Press a letter (not a number!) key to assign a slot to your macro.
  3. You are now recording. Do whatever you want with usual commands.
  4. Once you are done, press q again to stop recording.
  5. You can now run your recorded macro by pressing @ and its assigned letter key.

Cheats:

  • If you want to run a macro repeatedly, type a number before pressing the @ key. Example: ...

How to stub class constants in RSpec

Hint: There's another card with this helper for Cucumber features.


Sometimes you feel like you need to stub some CONSTANT you have defined in an other class. Since actually constants are called constants because they're constant, there's no way to easily stub a constant.

Here are three solutions for you.

Easiest solution

Rethink! Do you really need CONSTANT = %w[foo bar] to be constant? In many cases, setting it as a...

Always store your Paperclip attachments in a separate folder per environment

tl;dr: Always have your attachment path start with :rails_root/storage/#{Rails.env}#{ENV['RAILS_TEST_NUMBER']}/.


The directory where you save your Paperclip attachments should not look like this:

storage/photos/1/...
storage/photos/2/...
storage/photos/3/...
storage/attachments/1/...
storage/attachments/2/...

The problem with this is that multiple environments (at least development and test) will share the same directory structure. This will cause you pain eventually. Files will get overwritten and...

Nginx Error "413 Request Entity Too Large"

If you get the error "413 Request Entity Too Large" from Nginx client_max_body_size is too low (default is client_max_body_size=1m).

This can happen for example during file upload.

Check whether a Paperclip attachment exists

Don't simply test for the presence of the magic Paperclip attribute, it will return a paperclip Attachment object and thus always be true:

- if user.photo.present? # always true
  = image_tag(user.photo.url)

Use #exists? instead:

- if user.photo.exists?
  = image_tag(user.photo.url)

How to grep through the DOM using the Capybara API

When your Cucumber feature needs to browse the page HTML, and you are not sure how to express your query as a clever CSS or XPath expression, there is another way: You can use all and find to grep through the DOM and then perform your search in plain Ruby.

Here is an example for this technique:

Then /^I should see an image with the file...

Rails I18n fallback locales

When you need to create a locale for a language variant (like Austrian for German), you probably don't want to duplicate your entire de.yml file only to change a few minor exceptions for our Austrian friends.

Luckily, the I18n gem used by Rails has a fallback feature where you can make one locale file fall back to another if no translation is available.

In the example above you would have a config/locales/de_DE.yml:

de_DE:
  # hundreds of translations here

... and another...

Web Operations 101 For Developers

This post is not about devops, it's not about lean startups, it's not about web scale, it's not about the cloud, and it's not about continuous deployment. This post is about you, the developer who's main purpose in life has always been to build great web applications. In a pretty traditional world you write code, you write tests for it, you deploy, and you go home. Until now.

Responding to the OPTIONS HTTP method request in Rails: Getting around the Same Origin Policy

Code example for implementing Cross-Origin Resource Sharing (CORS) in Rails.

Zip files with Ruby

When you need to zip up files in Ruby, use zipruby.

sudo gem install zipruby

You can add existing files, add files from strings and even add directories.
Example usage:

require 'zipruby'
cars = %w[audi bmw mercedes]

zipfile = Tempfile.new('my.zip', 'tmp')
Zip::Archive.open(zipfile.path, Zip::CREATE) do |zip|
  zip.add_file '/tmp/me.txt'
  zip.add_dir 'cars' 

  cars.each do |car|
    zip.add_buffer "cars/#{car}.txt", "This #{car} is mine!" 
  end
end

Credits go to winebarrel for the Ruby bin...

Hide your Selenium browser window with a VNC server

This is now part of geordi. Please don't follow the instructions below, if you use geordi.

Inspired by the recent headless Selenium note, I found yet another solution for the problem to hide your selenium tests away.

This has the advantages
^

  • not to require a gem (so you do not force this on others)
  • to allow you to take a look at the running webdriver if necessary

Simply make a script th...

How to look at hidden X screens

When you have a program running in a hidden X screen (like with Xvfb for Selenium tests) you may want to look at that hidden screen occasionally.

First, find out what X displays are currently active:

netstat -nlp | grep X11

This should give you some results like these:

unix  2      [ ACC ]     STREAM     LISTENING     8029600  4086/Xvfb           /tmp/.X11-unix/X99
unix  2      [ ACC ]     STREAM     LISTENING     8616     -     ...