Virtual attributes for array fields

When a has_many association basically serves to store a list of associated strings (tags, categories, ...), it can be convenient to represent this association as a string array in the containing model. Here is an example for this pattern from the acts-as-taggable-on gem:

post = Post.last
p post.tag_list # ['foo', 'bar', 'baz']
post.tag_list = ['bam']
p post.tag_list # ['bam']

This string array tag_list is magical in several ways:

  • It is read from and written to a `has...

Hunt down that elusive debug message in Ruby

When you just went through a long debug-fest and infested your code with dozens of debug messages, it can be hard to find all those calls to puts and p. This note describes a hack that lets you trace those messages in your code.

Let's say you want to get rid of a console message "foobar". Copy the Undebug class below to config/initializers.rb. In the same initializer, type a line:

Undebug.trace_message('foobar')

Now run tests or whatever you need to do to to trigger that message. The console output should look like this:

...

Virtual attributes for integer fields

Note that this card is very old. You might want to use ActiveType for your auto-coerced virtual attributes instead.


We sometimes give our models virtual attributes for values that don't need to be stored permanently.

When such a virtual attribute should contain integer values you might get unexpected behavior with forms, because every param is a string and you don't get the magic type casting that...

Don't use migrations to seed default data

Don't insert table rows in a Rails database migration. This will break tests that expect that database to be empty and cause you all sorts of pain.

If you need a place for default application data, use db/seed.rb or put a script into lib/scripts. It won't run automatically, so add a chore story to Pivotal Tracker as a reminder.

Take care when joining and selecting on scopes

Occasionally some complex query must be processed on the database because building thousands of Ruby objects is impracticable.

Many times you would use scope options, like this:

users = User.scoped(
  :joins => 'INNER JOIN orders joined_orders ON users.id = joined_orders.user_id',
  :conditions => [ 'joined_orders.date BETWEEN ? AND ?', start_date, end_date ],
  :select => '*, SUM(joined_orders.amount) AS amount_sum',
  :group => 'users.id'
)

You get ActiveRecord objects and you can ask each of them about its `amou...

Manipulate an array attribute using multiple check boxes

E.g. when you're using a tagging gem, you have seen virtual attributes that get and set a string array:

post = Post.last
puts post.tag_list # ['foo', 'bar', 'baz']
post.tag_list = ['bam']
puts post.tag_list # ['bam']

If you would like to create a form displaying one check box per tag, you can do this:

- form_for @post do |form|
  = form.check_box :tag_list, { :multiple => true }, 'foo', nil
  = form.check_box :tag_list, { :multiple => true }, 'bar', nil
  =...

Test a gem in multiple versions of Rails

Plugins (and gems) are typically tested using a complete sample rails application that lives in the spec folder of the plugin. If your gem is supposed to work with multiple versions of Rails, you might want to use to separate apps - one for each rails version.

For best practice examples that give you full coverage with minimal repitition of code, check out our gems has_defaults and assignable_values. In particular, take a look at:

  • Multiple `sp...

Retrieve the total number of records when paginating with will_paginate

When you use will_paginage to paginate a scope, and you want to obtain the total number of records matched before pagination, you can use total_entries:

users = User.active.paginate
puts users.count # number of records on this page, e.g. 50
puts users.total_entries # total number of records before pagination, e.g. one billion trillion

This will trigger a second database query in order to retrieve the count (which will run anyway if you render any kind of pagination widget).


`wil...

Change the id of an ActiveRecord record

You most likely never want to do this. But if you do:

Model.update_all({:id => new_id}, {:id => old_id})

Migrate or revert only some migrations

To only run the next two migrations:

rake db:migrate STEP=2

To revert the previous two migrations:

rake db:rollback STEP=2

To revert the last two migrations and then migrate to the most current version:

rake db:migrate:redo STEP=2

To migrate to a given migration number, regardless of whether that means migrating up or down:

rake db:migrate VERSION=20100627185630

To migrate exactly one individual migration out of the sequence* (careful):

rake db:migrate:up VERSION=20100627185630

To revert exactly one individual m...

Select a random table row with ActiveRecord

Use this scope:

class Stick
  named_scope :shuffled, lambda {
    last_record = last
    { :conditions => [ 'id >= ?', rand(last_record.id) ] } if last_record
  }
end

You can now pick a random stick by saying

Stick.shuffled.first

Or, if you prefer something smaller:

class Stick
  named_scope :shuffled, :order => 'RAND()'
end

Note however that you should never order by RAND() on tables that may become large some day, as this performs horribly and can kill your database server.

Show a MySQL table's charset, collation and engine

Use this MySQL command to show further info about a table:

SHOW CREATE TABLE tags;

This will output a table schema like this:

CREATE TABLE `tags` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_tags_on_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Undocumented :inverse_of option for ActiveRecord associations

You can now add an :inverse_of option to has_one, has_many and belongs_to associations.... Without :inverse_of m and f.man would be different instances of the same object (f.man being pulled from the database again). With these new :inverse_of options m and f.man are the same in memory instance.

Migrating to RSpec 2 from RSpec 1

You will need to upgrade to RSpec >= 2 and rspec-rails >= 2 for Rails 3. Here are some hints to get started:

  • In RSpec 2 the executable is rspec, not spec.
  • RSpec and rspec-rails have been completely refactored internally. All RSpec classes have been renamed from Spec::Something to RSpec::Something. This also means that every require 'spec/something' must now be require 'rspec/something'.
  • In spec_helper.rb, Spec::Runner.configure becomes RSpec.configure
  • It has become really hard to extend specific example groups ...

Getting your e-mails back after upgrading Thunderbird to version 3

If you previously used version 2.x of Thunderbird and upgraded to 3.x (for example through an Ubuntu release upgrade) you might notice that Thunderbird will not show any of your old e-mails or settings.

This results from a different directory being used for storing profiles and configuration.

You can replace the blank profile with your old one like this:
cd ~
mv .thunderbird .thunderbird-invalid
cp -R .mozilla-thunderbird .thunderbird

Upon its next start, Thunderbird brings up the migration wizard introducing you to a few vers...

Working around the ancestry gem's way of object destruction

The ancestry gem allows you to easily use tree structures in your Rails application.

There is one somewhat unobvious pitfall to it: its way of applying the orphan_strategy which defines how it handles children of an object going to be destroyed.

What's this all about?

In many cases you might want to disallow destruction if there are any child nodes present. The restrict strategy does the trick but raises an exception when destroy is called:
has_ancestry :orphan_st...

Inspecting model callback chains

If you need to look at the list of methods that are called upon certain events (like before/after saving etc), do this:

Model._save_callbacks.select {|cb| cb.kind == :before}.map{ |c| c.instance_variable_get :@filter }

Rails 2

User.after_save_callback_chain

To look at the method names only, you could do something like that:

User.after_save_callback_chain.collect(&:method)

Dealing with ActiveRecord::RecordNotSaved

If you get an ActiveRecord::RecordNotSaved error, a method inside one of your model's callback chains (before_save etc) possibly returned false.

This commonly happens when you have a method setting attributes and the last one is a boolean set to false (as the value of the last statement is returned). Fix this by simply calling true at the end of such methods:

def hide
  self.visible = false
  true
end

Note that nil won't cause this behavior. Thus, you can use an if without problems -- if you are not returning fal...

Preload tags with acts-as-taggable-on

When you do tags with acts-as-taggable-on and want to preload associated tags, you can do so with

TaggedModel.scoped(:include => :tag)

Note however that this will only prevent tagged_model.tags from hitting the database. Using tagged_model.tag_list does not use the preloaded association.

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

apotonick's hooks at master - GitHub

Hooks lets you define hooks declaratively in your ruby class. You can add callbacks to your hook, which will be run as soon as you run the hook.

Sun Java JVM/JRE on Ubuntu Linux

Note that you should disable the Java plug-in in your browsers after installation.

Ubuntu >= 12.04

Java 11

sudo apt install openjdk-11-jre-headless

Java 10

sudo add-apt-repository ppa:linuxuprising/java
sudo apt-get update
sudo apt-get install oracle-java10-installer

Java 8

You probably want to get rid of OpenJDK (which is installed by default and leads to bad RubyMine performance):

...

Save ActiveRecord models without callbacks or validations (in Rails 2 and Rails 3)

Rails 2

You can use

record.send(:update_without_callbacks)

or

record.send(:create_without_callbacks)

This can be used as a lightweight alternative to machinist's make or FactoryGirl's create, when you just need objects in the database but don't care about any callbacks or validations. Note that create_without_callbacks does not return the object, so you might want to do

record = Record.new.tap(&:create_without_callbacks)

Rails 3

Rails 3 no longer comes with update_without_callbacks or `crea...

Security issues with hash conditions in Rails 2 and Rails 3

Find conditions for scopes can be given either as an array (:conditions => ['state = ?', 'draft']) or a hash (:conditions => { 'state' => 'draft' }). The later is nicer to read, but has horrible security implications in some versions of Ruby on Rails.

Affected versions

Version Affected? Remedy
2.3.18 yes Use chain_safely workaround
3.0.20 no ...