BigDecimal arithmetic in Ruby

Ruby comes with a class BigDecimal which you can use for arbitrary precision arithmetic. You should use BigDecimal instead of Float whenever you care about rounding errors, e.g. whenever you are dealing with money.

You should remember these two rules when working with BigDecimal values:

  • When you add or multiply a BigDecimal with another BigDecimal, the ...

How DECIMAL columns deal with numbers exceeding their precision or scale

When storing floating-point numbers such as prices or totals in an SQL database, always use a DECIMAL column. Never use FLOAT or kittens will die.

DECIMAL columns are parametrized with a precision and a scale. These parameters describe which numbers can be stored in that column. E.g. a decimal with a precision of 5 and a scale of 2 can store numbers from -999.99 to 999.99, but not 1000 or 1.234.

This card explains what various databases do when you try to store a number in a DECIMAL field, and that number exceeds that colum...

Capistrano 2: Which Capistrano hooks to use for events to happen on both "cap deploy" and "cap deploy:migrations"

When deploying an application with "cap deploy" by default [1] you only deploy your code but do not run migrations. To avoid an application to be running with code which requires database changes that did not happen yet you should use cap deploy:migrations.

The problem

Let's say that you have something like that in your config/deploy.rb to create a database dump every time you deploy:

before 'deploy', 'db:dump'

This will not be called for cap deploy:migrations. The same applies to other things that are ho...

Saving application objects in your session will come back to haunt you

If you save a non-standard object (not a String or Fixnum, etc) like the AwesomeClass from your application in the session of visitors be prepared that some time you will get this exception:

ActionController::SessionRestoreError: Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: ...)

This happens when you remove your AwesomeClass but users come back to your site and still have the serialization of such objects in their session....

Collect an array of IDs from any object

The Edge Rider gem will define a method collect_ids on your ActiveRecord models, scopes, integer scalars and collections, which will return a list of their IDs:

User.last.collect_ids # => [9]
[User.first, User.last].collect_ids # => [1, 9]
User.active.collect_ids # => [4, 5, 6]
[4, 5, 6].collect_ids # => [4, 5, 6]
7.collect_ids #=> [7]

This allows you to parametrize scopes with a variety of argument types:

class Note < ActiveRecord::Base
  named_scope :for_users, lamb...

Why preloading associations "randomly" uses joined tables or multiple queries

ActiveRecord gives you the :include option to load records and their associations in a fixed number of queries. This is called preloading or eager loading associations. By preloading associations you can prevent the n+1 query problem that slows down a many index view.

You might have noticed that using :include randomly seems to do one of the following:

  1. Execute one query per involved table with a condit...

Retrieve the SQL query a scope would produce in ActiveRecord

Rails 3

User.active.to_sql

Rails 2

Use either the Edge Rider or fake_arel gem to get #to_sql backported to Rails 2.

If you don't want to use a gem for this, you can do this with vanilla Rails 2:

User.active.construct_finder_sql({})

Cast an ActiveRecord to a subclass or superclass

Note: ActiveRecord::Base#becomes has a lot of quirks and inconsistent behavior. You probably want to use ActiveType.cast instead.


ActiveRecord models have with a method becomes(klass) which you can use to cast the record into an instance of its subclasses or superclass. This is useful because some parts of Rails reflect on the class of an instance, e....

Imperative vs Declarative Scenarios in User Stories

Bryan talked about the differences between imperative and declarative scenarios. In my opinion, both styles have benefits and should be used appropriately based on the situation. The majority of examples on rspec's story runner currently on the web, including mine, are of the imperative type. Since the declarative type has many advantages I thought it would be worth while to present some examples and contrast the differences between the two styles.

Do not deliver mails when there are no recipients set

When using ActionMailer, you can set an array of email addresses as recipients. If this array is generated by e.g. collecting email addresses from the database, it might sometimes be empty.

To prevent ActionMailer to deliver mails to nobody, simply overwrite the deliver! method like this:

# In your mailer.rb
def deliver!(mail = @mail)
  return false if (recipients.nil? || recipients.empty?) && (cc.nil? || cc.empty?) && (bcc.nil? || bcc.empty?)
  super
end

Caching in Rails

The information in this card is only relevant for Rails 2.3-era apps.


This note gives a quick introduction into caching methods (page caching, action caching and fragment caching) in rails and describes some specific problems and solutions.

The descriptions below are valid for Rails 2 and 3. Recently, caching with timestamp- or content-based keys has become more popular which saves you the pain of invalidating stale caches.

How to enable/disable caching

To enable or disable caching in rails you ca...

Prevent an ActiveRecord attribute from being changed after creation

Sometimes you can make your life easier by not allowing a record attribute to be changed after the record was created. An example for this is when your model represents a child node in a composition and has logic that is hard to support for cases when the container changes.

Here is an example for a container Region composed of many children of type Holiday. After saving a Holiday it caches the current number of holidays in its region:

class Region < ActiveRecord::Base

...

Touch records without running callbacks

ActiveRecord comes with a method touch which sets the updated_at timestamp to the current time. Unfortunately it also runs callbacks (and hence validations) on the receiving record, so it is unsuitable if you call it very often.

Use the attached initializer to get a touch_gently method which updates updated_at, but does not run callbacks:

User.find(5).touch_gently

The initializer will also give you a method touch_all_gently whi...

Upgrading Cucumber and Capybara to the latest versions available for Rails 2

Specify these gem versions in your Gemfile:

gem 'cucumber', '~> 1.3.0'
gem 'cucumber-rails', '= 0.3.2' # max version for Rails 2
gem 'capybara', '< 2' # capybara 2+ requires Rails 3
gem 'mime-types', '< 2' # dependeny of capybara
gem 'nokogiri', '< 1.6' # dependency of capybara
gem 'rubyzip', '< 1' # dependency of selenium-webdriver, rubyzip 1+ requires Ruby 1.9
gem 'cucumber_factory'
gem 'database_cleaner', '< 1'
gem 'cucumber_spinner', '~> 0.2.5'
gem 'launchy', '~> 2.1.2'

With these versions set, `...

Onload callback for dynamically loaded images

Sometimes you need to dynamically load an image and do something as soon as its loaded (when for example its size is already available).

With jQuery, this seems to work across browsers:

$('<img>')
  .attr('src', '')
  .load(function() {
    alert('fully loaded!');
  })
  .attr('src', '/the/real/image/url');

Customize your Bash prompt

The shell variable PS1 holds your bash prompt. You might want to change it to serve your needs best. Here is how to:

General

  • non-printing escape sequences in your prompt have to be inclosed in \[\e[ and \] so your shell can correctly count its prompt's length
  • we recommend to highlight your prompt on production machines
  • you can also [show different root prompts for each user](https://makandracards.com/makandra/9569-get-the-username-w...

Ruby and Rails deprecation warnings and how to fix them

Add deprecation warnings and their solution or link to available solutions.

Global access to Rake DSL methods is deprecated. Please include Rake::DSL into classes and modules which use the Rake DSL methods.

Open your Rakefile and add the following line above YourApp::Application.load_tasks:

YourApp::Application.class_eval do
  include Rake::DSL
end

Use of ole/file_system is deprecated. Use ole/storage (the file_system api is recommended and enabled by default)...

CSS3 Pie: Element not properly redrawn

Pie sometimes does not properly redraw elements upon changes. This often happens when the change comes from somewhere further up the DOM.

Consider something like:

<ul>
  <li class="active"><div class="content">Active element</div></li>
  <li class="inactive"><div class="content">Inactive element</div></li>
</ul>

with CSS
li .content {
-webkit-box-shadow: #666 0px 2px 3px;
-moz-box-shadow: #666 0px 2px 3px;
box-shadow: #666 0px 2px 3px;
behavior: url(/PIE.htc);

  back...

JavaScript Garden

JavaScript Garden is a growing collection of documentation about the most quirky parts of the JavaScript programming language. It gives advice to avoid common mistakes, subtle bugs, as well as performance issues and bad practices that non-expert JavaScript programmers may encounter on their endeavours into the depths of the language.

JavaScript Garden does not aim to teach you JavaScript. Former knowledge of the language is strongly recommended in order to understand the topics covered in this guide

RSpec matcher to check if an ActiveRecord exists in the database

The attached RSpec matcher exist_in_database checks if a given record still exists in the database and has not been destroyed:

describe Ticket do
  describe '.purge_expired' do
    fresh_ticket = Ticket.create(:expiry => Date.tomorrow)
    expired_ticket = Ticket.create(:expiry => Date.yesterday)
    Ticket.purge_expired
    fresh_ticket.should exist_in_database
    expired_ticket.should_not exist_in_database
  end
end

Note that there is also [ActiveRecord::Base#destroyed?](http://apidock.com/rails/ActiveRecord/Base/destroyed...

ActiveRecord: Creating many records works faster in a transaction

When you need to insert many records into the same table, performance may become an issue.

What you can do to save time is to open a transaction and save multiple records within that transaction:

transaction do
  500.times { Model.create! }
end

Although you will still trigger 500 INSERT statements, they will complete considerably faster.

When I tried it out with a simple model and 500 iterations, the loop completed in 1.5 seconds vs. 6 seconds without a transaction.

Alternative

Another fast way to insert many ...

Deal with different ways of counting weeks and weekdays in Ruby

Depending on where you live, different rules are used to determine the number of the week and a weekday. You have no chance whatsoever to get this right globally unless you make it your life's purpose. However, when you work for clients from Europe or the US, there are two dominantish standards you should know about. Each of these has subtle differences.

ISO 8601

  • This is adhered to by most European countries.
  • Weeks start on Mon...

Find records with a Range condition

You can find ActiveRecord models by using a Range as its conditions:

User.scoped(:conditions => { :id => 3..5 })

This will generate the following query:

SELECT * FROM `users` WHERE (`users`.`id` BETWEEN 3 AND 5)

This also means that all your scopes that take an array of allowed values and use condition hashes, automagically work for Ranges, too.

Output the descriptions of RSpec examples while they are running

In order to

  • track down warnings and to see failing specs immediately
  • or to get an overview of the core functionalities,

you can use RSpec's "nested" format. It looks like this:

Tool
  validations
    should require model to be set
    should require place_id to be set
  #identifier
    should include the model and tag if the tool has a tag
    should return the model if the tool has no tag
  .search
    should find tools by model and maker
    should find tools by serial number

Call RSpec like...