How could it be that my database.yml disappears?

Probably was in the repository once and got deleted in a commit that you pulled.

Plotting graphs in Ruby with Gruff

Geoffrey Grosenbach has created Gruff for easily plotting graphs. It is written in pure Ruby and integrates with Rails applications.

It provides features as automatic sizing of dots and lines (the more values, the thinner the graph's elements), custom or predefined themes, different styles (bar, line, dot and many more) and multiple graphs in one chart.

Installation

In your Gemfile:

gem 'rmagick', :require => false
gem 'gruff'

Then run bundle install (and don't forget to restart your development server.)

Usage

This i...

The Ruby Toolbox – a collection of good gems

If you need a gem for a certain purpose, be sure to check this site.


The rankings are determined by counting up the number of forks and watchers of various github projects, so I'd view it less as "this is what I should be using," and more as "these are some things I should check out." At the very least, they're all likely to be under active development and fairly up to date, and it's very useful to see groups of gems broken down by category.

Guide to localizing a Rails application

Localizing a non-trivial application can be a huge undertaking. This card will give you an overview over the many components that are affected.

When you are asked to give an estimate for the effort involved, go through the list below and check which points are covered by your requirements. Work with a developer who has done a full-app localization before and assign an hour estimate to each of these points.

Static text

  • Static strings and template text in app must be translated: Screens, mailer templates, PDF templates, helpe...

MySQL 5.1: Switch to InnoDB Plugin for better performance

MySQL version 5.1 comes with an alternative, faster InnoDB implementation (called "InnoDB Plugin").

Switching is easy:

  • Stop your mysqld with sudo stop mysql
  • Add the following lines to your /etc/mysql/my.cnf under the [mysqld] section
    ignore-builtin-innodb
    plugin-load=innodb=ha_innodb_plugin.so
  • Start your mysqld with sudo start mysql

The file format has not changed, your tables should survive this.

Note: This is not necessary in MySQL 5.5, where the new implementation is the default.

How to use pessimistic row locks with ActiveRecord

When requests arrive at the application servers simultaneously, weird things can happen. Sometimes, this can also happen if a user double-clicks on a button, for example.

This often leads to problems, as two object instances are modified in parallel maybe by different code and one of the requests writes the results to the database.

In case you want to make sure that only one of the requests "wins", i.e. one of the requests is fully executed and completed while the other one at least has to wait for the first request to be completed, you ha...

When using time zones, beginning_of_day / end_of_day is broken in Rails 2 for any Date or DateTime

Using beginning_of_day or end_of_day on Date or DateTime objects in Rails 2.x applications will never respect time zones, which is horrible.\
This is fixed in Rails 3, though.

Even when using Date.current or DateTime.current you will get regular Time or DateTime objects:

>> Date.current.beginning_of_day.class
=> Time # not a ActiveSupport::TimeWithZone as expected
>> DateTime.current.beginning_of_day.class
=> DateTime ...

salesking/king_dtaus

DTAUS & DTAZV are formats for German bank transfers and is short for "Datenträgeraustausch". The format itself totally sucks because it was established in the last century, to be used on floppy disks. Still almost all German banks use it (they only seem innovative at robbing), and it is therefore supported in common banking programs too.

This gem saves you all the trouble when generating DTAUS- or DTAZV-text.

Why has_many :through associations can return the same record multiple times

An association defined with has_many :through will return the same record multiple times if multiple join models for the same record exist (a n:m relation). To prevent this, you need to add ->{ uniq } as second argument to has_many (below Rails 4 it is a simple option: has_many :xyz, :uniq => true).

Example

Say you have an Invoice with multiple Items. Each Item has a Product:

class Invoice < ActiveRecord::Base
  has_many :items
  has_many :products, :through => :items
end

class Item < ActiveRecord::Base
  ...

Validate attachment presence using paperclip

Make sure you call the methods in the following order and not vice versa:

has_attached_file :image
validates_attachment_presence :image

Validation with condition works fine, too:

validates_attachment_presence :image, :if => :method

This is because validates_attachment_presence is only available after saying has_attached_file.

Shell script to deploy changes to production and not shoot yourself in the foot

Geordi, our collection of command line tools, has been extended by another command deploy-to-production. This script encapsulates the following workflow:

  • Pull the production branch.
  • Show which commits from the master would make it to production with this deploy.
  • Ask if you want to proceed.
  • If yes, merge the master into the production branch, push and deploy with bundle exec cap production deploy:migrations

The script will ask you for the names of your master branch, production branch an...

validates_acceptance_of is skipped when the attribute is nil

validates_acceptance_of :terms only works if terms is set to a value. The validation is skipped silently when terms is nil.

While this behavior is useful to validate acceptance in the frontend and not the admin backend, it also makes it very easy to unintentionally skip the validation altogether by forgetting to add the checkbox to a form. E.g. validates_acceptance_of :terms_with_typo will be skipped silently even if there is no column with t...

Change how Capybara sees or ignores hidden elements

Short version

  • Capybara has a global option (Capybara.ignore_hidden_elements) that determines whether Capybara sees or ignores hidden elements.
  • Prefer not to change this global option, and use the :visible option when calling page.find(...). This way the behavior is only changed for this one find and your step doesn't have confusing side effects.
  • Every Capybara driver has its own notion of "visibility".

Long version

Capybara has an option (Capybara.ignore_hidden_elements) to configure the default...

Customize path for Capybara "show me the page" files

When you regularly make use of Cucumber's "show me the page" step (or let pages pop up as errors occur), the capybara-20120326132013.html files will clutter up your Rails root directory.

To tell Capybara where it should save those files instead, put this into features/support/env.rb:

Capybara.save_and_open_page_path = 'tmp/capybara'

Fix [RubyODBC]Cannot allocate SQLHENV when connecting to MSSQL 2005 with Ruby 1.8.7. on Ubuntu 10.10

I followed this nice guide Connecting to MSSQL with Ruby on Ubuntu - lambie.org until I ran in the following errors:

irb(main):001:0> require "dbi"; dbh = DBI.connect('dbi:ODBC:MyLegacyServer', 'my_name', 'my_password')

DBI::DatabaseError: INTERN (0) [RubyODBC]Cannot allocate SQLHENV
  from /usr/lib/ruby/1.8/dbd/odbc/driver.rb:36:in `connect'
  from /usr/lib/ruby/1.8/dbi/handles/driver.rb:33:in `connect'
  from /usr/lib/ruby...

ActiveRecord: Overwriting a setter causes trouble with attributes depending on each other

Undeterministically I got a nil error on saving the object caused by the random order of hash elements of the params hash.

class Feedback
  belongs_to :user

  def role=(value)
    @role = value
    self.email = find_email_by_name(user.name)
  end
end

This piece of code works well until the object params hash contains a second element when it is updated like this:

@feedback.update_attributes!(params[:feedback])

Now it is no longer ensured that user was set before name was set. If the name...

Creating the inverse of a Rails migration

Let's say you need to revert a migration that happened a while back. You'd create a new migration that removes what was added back then in the up path, while its down path restores the old functionality.

While you could just copy&paste the down and up parts of it to the inverse part of the new migration, you may not want to do that. Especially when the up/down paths already contained some logic (that executed update statements on the created column, for example), copying does not feel right.

Someone already added the logic how to...

Gatekeeping: Guide for developer

If your project manager wants to do gatekeeping on a project, as a developer you need to follow the following guidelines (e.g. by using something like this issue checklist template).

In order to reduce the number of rejects we get from clients, we want to review all code written before it goes to the staging server.

Note

This process is tailored to our specific needs and tools at makandra. While it will certainly not apply to all (especially larger teams), we think it...

TeamViewer 7 finally works with multiple screens under Linux

TeamViewer 6 and lower had an issue where they would see a multi-monitor Linux setup as a single wall of pixels. This is fixed in version 7. The guest can now select the currently active screen from the TeamViewer menu.

ActiveRecord: When aggregating nested children, always exclude children marked for destruction

When your model is using a callback like before_save or before_validation to calculate an aggregated value from its children, it needs to skip those children that are #marked_for_destruction?. Otherwise you will include children that have been ticked for deletion in a nested form.

Wrong way

class Invoice < ApplicationRecord
  has_many :invoice_items
  accepts_nested_attributes_for :invoice_items, :allow_destroy => true # the critical code 1/2
  before_save :calculate_and_store_amount                              # the crit...

will_paginate on complex scopes may be slow (workaround)

will_paginate triggers a database query to determine the total number of entries (i.e. to let you display the number of search results). When you paginate complex scope (e.g. that has many includes), this query may take several seconds to complete.

If you encounter this behavior, a solution is to calculate the total count yourself and pass it to the pagination call:

scope = User.complex_scope_full_of_includes
total_number_of_users = scope.count
@users = scope.paginate(:total_entr...

In MySQL, a zero number equals any string

In MySQL comparing zero to a string 0 = "any string" is always true!

So when you want to compare a string with a value of an integer column, you have to cast your integer value into a string like follows:

SELECT * from posts WHERE CAST(posts.comments_count AS CHAR) = '200' 

Of course this is usually not what you want to use for selecting your data as this might cause some expensive database operations. No indexes can be used and a full table scan will always be triggered.

If possible, cast the compared value in your application to...