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

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

Cast a string to the type of an ActiveRecord attribute

ActiveRecord models know how to cast a given string to the type of a given attribute (or column).

The following model will serve as our example:

create_table :notes do |t|
  t.string :title
  t.integer :user_id
  t.boolean :deleted
end

You can make the Note class cast strings into their respective types like this:

Note.columns_hash['user_id'].type_cast('123') # => 123
Note.columns_hash['deleted'].type_cast('1') # => true
Note.columns_hash['deleted'].type_cast('0') # => false

How to send HTTP requests using cURL

  • Reading a URL via GET:

    curl http://example.com/
    
  • Defining any HTTP method (like POST or PUT):

    curl http://example.com/users/1 -XPUT
    
  • Sending data with a request:

    curl http://example.com/users -d"first_name=Bruce&last_name=Wayne"
    

    If you use -d and do not set an HTTP request method it automatically defaults to POST.

  • Performing basic authentication:

    curl http://user:password@example.com/users/1
    
  • All together now:

    curl http://user:password@example.com/users/1 -XPUT -d"screen_name=batman"
    

...

How to perform HTTP basic authentication in RSpec

The Basic Authentication header encodes username and password. Effectively, it's just Base64 plus a "Basic" prefix.
You can use ActionController::HttpAuthentication::Basic.encode_credentials for that, and put its result into the Authorization request header.

Request specs

For request specs, use the :header option.

it 'requires authentication' do
  get '/'
  expect(response.status).to eq(401)
end

it 'accepts valid credentials' do
  encoded_credentials = ActionController::HttpAuthentication::Basic.encode_credentials(use...

Default views in Rails 3.0 with custom resolvers

It is common in Rails 3.0 applications that you want to provide default views for a group of controllers. Let’s say you have a bunch of controllers inside the Admin namespace and you would like each action to fallback to a default template. So if you are rendering the index action for Admin::PostsController and “app/views/admin/posts/index.html.*” is not available, it should then render “app/views/admin/defaults/index.html”.

Since Rails 3.0, we have a new abstraction called resolvers that holds the logic to find a template.

How to send a test e-mail from shell

If you want to manually check if e-mail delivery works on a machine by sending an e-mail you can run the following:
mail -s Test someone@example.com < /dev/null

This will send an empty e-mail with "Test" as its subject to someone@example.com.

If you want it to contain a message body, call mail -s Test someone@example.com only; the mail application will then read your input from stdin. Finish your message by sending EOT with Ctrl-D -- if you are asked for anything else ...

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.

Where to put custom RSpec matchers

When you write a custom RSpec matcher a good place to store them is to create one file per matcher in spec/support/matchers:

spec/support/matchers/be_same_numbers_as.rb
spec/support/matchers/be_same_second_as.rb
spec/support/matchers/exist_in_database.rb
spec/support/matchers/include_hash.rb

You can include all matchers in the support directory by adding the following line to your spec_helper.rb:

Dir[File.expand_path(File.join(File.dirname(__FI...

Test that a hash contains a partial hash with RSpec

To test whether a hash includes an expected sub-hash:

expect(user.attributes).to match(hash_including('name' => 'Bruce Wayne'))
expect(User).to receive(:create!).with(hash_including('name' => 'Bruce Wayne'))

Acceptance testing using Capybara's new RSpec DSL

Back when Steak was first released, Capybara didn’t have any of the nice RSpec helpers it does now. A lot has changed since. Besides the helpers, it got its own RSpec acceptance testing DSL recently, essentially eating Steak’s functionality and turning it into a complete acceptance testing solution (on top of RSpec).

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

Liquid Canvas

Liquid Canvas is a JavaScript library which allows you to draw inside an HTML canvas element with an easy yet powerful description language.

It can be used to add graphics to your web page without ever touching an image creation tool such as The Gimp, Inkscape or Photoshop.

Check out the Demo and the basic example and then download version 0.3.

Upgrade from Ruby 1.8.7 to Ruby 1.9.2 on Ubuntu

Note that you cannot currently use Ruby 1.9.2 with Rails 2 applications that use RSpec, so don't upgrade if that is your setup. The rspec-rails gem has a fatal bug that was only fixed for rspec-rails-2.x, which only supports Rails 3. There is no fix for the rspec-rails-1.3.x series of the gem which supports Rails 2.

Anyway, here are upgrade instructions if you only work with Rails 3 or don't use RSpec. You will lose all your gems in the process, but you can get them back easily if you h...

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

...

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

Sanitize user-generated filenames and only send files inside a given directory

If in your application your users pass along params that result in filenames, like invoices/generated?number=123. This could be your (very careless) controller method:

def generated
  send_file File.join(Rails.root, 'shared', 'invoices', params[:number])
end

This allows your users not only to access those files but also any files your application can read, like this:

invoices/generated?number=../../../../../etc/passwd
# => send_file '/etc/passwd'

You do not want this. In most cases you should prefer a show met...

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

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

Mocks and stubs in Test::Unit when you are used to RSpec

We are maintaining some vintage projects with tests written in Test::Unit instead of RSpec. Mocks and stubs are not features of Test::Unit, but you can use the Mocha gem to add those facilities.

The following is a quick crash course to using mocks and stubs in Mocha, written for RSpec users:

|---------------------------------------------------------|
| RSpec | Mocha |
|---------------------------------------------------------|
| obj = double() | obj = mock() |
| obj.stub(:method => 'value') | `obj.stubs...

Alternative to url_for's deprecated :overwrite_params option

If you have the following deprecation warning after upgrading to rails >= 2.3.10

DEPRECATION WARNING: The :overwrite_params option is deprecated. Specify all the necessary parameters instead.

that is for example caused by

url_for( :overwrite_params => { :order => 'name', :dir => 'asc' } )

you can fix this by using params.merge {:my_param_to_overwrite => 'foo' }.
To fix the example above the code could look like:

url_for( params.merge { :order => 'name...

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