MySQL: Disable query cache for database profiling

If you want to see how long your database queries actually take, you need to disable MySQL's query cache. This can be done globally by logging into a database console, run

SET GLOBAL query_cache_type=OFF;

and restart your rails server.

You can also disable the cache on a per query basis by saying

SELECT SQL_NO_CACHE * FROM ...

You also probably want to disable Rails internal (per-request) cache. For this, wrap your code with a call to ActiveRecord::Base.uncached. For example, as an around_filter:

d...

Generate a strong secret from the shell

A good tool to generate strong passwords and secrets is "apg". You can get it with

sudo apt-get install apg

To create a strong secret for sessions, hashed Paperclip paths, etc. say

apg -m128 -a1 -E\'\"

Arguments explained:

  • The -m parameter defines the secret length
  • -a1 makes apg choose from all 7-bit ASCII characters instead of just the alphabet
  • -E\'\" excludes quote characters so you can easily paste the secret into a Ru...

Reload the page in your Cucumber features

Both these approaches will keep your GET parameters -- and will only work for GET requests.

  • Capybara:

    When /^I reload the page$/ do
      visit [ current_path, page.driver.request.env['QUERY_STRING'] ].reject(&:blank?).join('?')
    end
    
  • Webrat:

    When /^I reload the page$/ do
      visit url_for(request.params)
    end
    

For a step that distinguishes between drivers (Selenium, Rack::Test, Culerity), check [n4k3d.com](http://n4k3d.com/blog/2011/02/02/reloading-the-page-in-cucumber-with-capybara-and-seleniu...

Deliver Paperclip attachments to authorized users only

When Paperclip attachments should only be downloadable for selected users, there are three ways to go.
The same applies to files in Carrierwave.

  1. Deliver attachments through Rails

The first way is to store Paperclip attachments not in the default public/system, but in a private path like storage inside the current release. You should prefer this method when dealing with sensitive data.

Make ...

Create a valid RSS feed in Rails

This will show you how to create a RSS feed that the Feed Validator considers valid.

Note that RSS is a poorly specified format. Consider using the Atom builder to make an Atom feed instead. Write a note here if you do.

  1. Controller

Create a FeedsController to host the RSS feed. Such a controller is also useful to host other data feeds that tend to gather over the lifetime of an application, e.g. sitemap.xml.:

class...

Remove resource fork files from a FAT volume on MacOS

Be careful!
The following solution will delete files on a volume. If you don't know exactly what you're doing, you can run into big trouble with your computer.

I play mp3 files on my car stereo that are stored on a SD-Card.
When I've copied those mp3 files to the FAT formatted SD-Card on my Mac, then I will see those nasty resource fork files (beginning with "._") for every file and folder on my car stereo. In most cases those resource fork files are important and invisible and don't bother you – on my car stereo ...

Debug Ruby code

This is an awesome gadget in your toolbox, even if your test coverage is great.

  • gem install ruby-debug (Ruby 1.8) or gem install debugger (Ruby 1.9)
  • Start your server with script/server --debugger
  • Set a breakpoint by invoking debugger anywhere in your code
  • Open your application in the browser and run the code path that crosses the breakpoint
  • Once you reach the breakpoint, the page loading will seem to "hang".
  • Switch to the shell you started the server with. That shell will be running an irb session where you can step thr...

Difference between respond_to/format and params[:format]

To return non-HTML responses (like XLS spreadsheets), we usually use the

respond_to do |format|
  format.xls do
    # send spreadsheet
  end
end

This is often, but not always the same as checking for params[:format] == :xls, so don't rely on this when e.g. one format checks for authorization and the other doesn't.

params[:format] is only set when a user explicitly puts a .xls at the end of the URL.

The format.xls block also responds when the user's browser requests the application/excel MIME type.

If Internet Explo...

Setting expiry dates for images, JavaScript and CSS

When deploying Rails applications you might have noticed that JS and CSS are not cached by all browsers.

In order to force Apache to add expiry dates to its response, add the attached .htaccess to the public directory. This will add a header such as Expires: Thu, 07 Oct 2010 07:21:45 GMT to the httpd response.

Configuring Apache

Check that you have mod_expires enabled. You need it for the attached .htaccess to work:

sudo a2enmod expires

Configuring Nginx

You can add this:

Spec correct routing of custom URLs

When you roll custom URLs with hacks like routing-filter, you can put a spec like this into spec/routing/routing_spec.rb:

How Rails and MySQL are handling time zones

When working with times and dates in Rails applications, you need to deal with the following problem:

  • In Rails, Time objects have a time zone. You can get the zone name by doing time_object.zone.
  • This zone is considered when doing time calculations, e.g. 10 AM CEST minus 8 AM UTC is zero.
  • A datetime in MySQL does not have a zone. It just stores the literal string "2010-05-01 12:00:00".
  • That means that Rails must make assumptions about timestamps loaded from and written to MySQL.

Rails has two completely different modes ...

Change Paperclip secrets the hard way

So you screwed up and copied Paperclip secrets from one project to another. Here is a semi-automatic, painful way to migrate your existing attachment files to new locations.

You need to follow this step by step, do not just copy the whole thing into the console!

# 1. Get old paths by doing something like this on the console:
old_paths = ModelWithAttachment.all.collect { |m| [m.id, File.dirname(m.image.path(:original)).gsub(/original$/, '') ] if m.image.file? }.compact.uniq

# 2. Now change the Paperclip secret on the co...

Marry Capybara with SSL-enabled applications

Capybara does not play nice with sites that have some actions protected by SSL, some not. A popular way to implement this in Rails is using the ssl_requirement plugin by DHH, which redirects a requests from HTTP to HTTPS if the requested action requires SSL and vice versa.

Capybara follows the redirect, but seems to forget the changed protocol for the next request. The only hack-free workaround right now is to use URLs in lieu of paths everywhere (links, form actions).

For a hackful fi...

Load all models into an Array

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

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...

Freeze (vendor, unpack) a single Ruby gem with and without Bundler

When you need to patch an existing gem, one way is to "vendor" the gem by copying it into the vendor/gems directory of your Rails project. You can then make any changes you require and Rails will use the vendored version of the gem after a server restart. Unfortunately you need to perform some additional steps to marry Rails and the copied gem. This notes describes what to do.

With Bundler

This is super-painful. If you just copy the gem to vendor/gems, Rails will complain:

Unpacked gem foolib in vendor/gems has no s...