Bundle install in parallel

Gave a shot to the new Bundler 1.4.0RC1 during the weekend and found out it now supports gem installation in parallel. To invoke you need to pass --jobs parameter with number of threads you want it to run – for me the best performance was achieved by specifying the number physical CPU cores.

I've tested on the AppFab app. In my case (CPU with 2-core i7 with HT) the speedup was 50%. I've also tried with a number greater than the number of physical cores but the performance was 15%-20% worse.

Bundler 1.3...

jQuery ajax success/done will not run callbacks if request is json but the response is empty (typical 200)

When using

var onDone = function() { ... }
var onFail = function() { ... }
var params = { ... }
var url = ...

$.ajax({
  type:  'put',
  url:  url,
  contentType: 'application/json; charset=utf-8',
  data:  JSON.stringify(params),
})
.done(onDone)
.fail(onFail);

Always make sure your rails controller returns something:

if @property.update_attributes(params[:property])
  render :json => { :ok => true }, :status => :ok
else
  render :json => { :ok => false }, :status => :unpro...

If you GROUP BY, make sure you ORDER BY NULL

TL;DR: If using :group => :some_field you might want to :order => 'NULL'.

According to the man

By default, MySQL sorts all GROUP BY col1, col2, ... queries as if you specified ORDER BY col1, col2, ... in the query as well. If you include an ORDER BY clause explicitly that contains the same column list, MySQL optimizes it away without any speed penalty, although the sorting still occurs. If a query includes GROUP BY but you want to avoid the overhead of sorting ...

DateTimes are Dates, beware

Given:

datetime = DateTime.now
date = datetime.to_date #or Date.today

will assert:

datetime.is_a? Date == true
datetime.is_a? DateTime == true
datetime.instance_of? Date == false
datetime.instance_of? DateTime == true

In case you have a table and a model like:

create_table :event do |t|
  t.date    :day
  t.string  :description
end
class Event < ActiveRecord::Base; end

And you say:

event = Event.new(:day => '2013-03-22')

Rails will convert the supplied value for day to the type of the database field,...

When you set date attributes, you should not pass times

As you know, time zones make stuff a bit more difficult but are necessary.

A time-zoned record is converted to UTC using to_s(:db) to be stored, and put back into the correct time zone when loaded. So when you are not on UTC, the following will happen:

>> Time.current
=> Fri, 15 Mar 2013 11:56:03 CET +01:00
>> Time.current.to_s(:db)
=> "2013-03-15 10:56:03" # This is now UTC

That will blow up in your face when you sen...

Profiling Ruby with ruby-prof

require 'ruby-prof' # you don't need this if you have ruby-prof in your Gemfile

You can set one of the things you want to measure by using (default is PROCESS_TIME most useful ones are PROCESS_TIME, MEMORY, CPU_TIME):
RubyProf.measure_mode = RubyProf::PROCESS_TIME
RubyProf.measure_mode = RubyProf::WALL_TIME
RubyProf.measure_mode = RubyProf::CPU_TIME
RubyProf.measure_mode = RubyProf::ALLOCATIONS
RubyProf.measure_mode = RubyProf::MEMORY
RubyProf.measure_mode = RubyProf::GC_RUNS
RubyProf.measure_mode = ...

Database: Scopes, migrations, and indices

Wether you modify an existing named scope or add a new one, or when you write a new query, make sure you have the proper indices.

This particularly applies if you're going to run non-trivial queries of course (admin backends, analytics, etc).

Compound indices

A chain of scopes results in (usually) one query. You should take into account all attributes (columns) that are used in :conditions, :join, :group, :having, and :order, as all those result in filtering and sorting–slow operations without indices.

Take the list of all ...

Add indexes on foreign keys when you create a migration (with foreign key)

Whenever you make a migration to add a foreign key, you should also add an index for it

  def self.up
    add_column :comments, :user_id, :integer
    add_index :comments, :user_id
  end

Writing raw SQL queries

If you really, really have a good reason to write raw SQL (generally a bad practice), make sure you use the right call.

Avoid ActiveRecord::Base.connection.execute in general, in particular because Octopus relies on this to determine which queries go to replicas. execute would always go to the master.

A number of other methods are available: select_value, select_rows, of update being the most usual.

ActiveRecord::NamedScopes (2.3.x) obtaining the SQL conditions

It's a good pratice to chain several named scopes like:

Property.listable.for_2_or_more_guests.best_10_properties

Now, to make the lesson more valuable let's assume the following code:

Property.scoped(:conditions => "foo = 2").scoped(:conditions => "foo2 IS NOT NULL")

Next, if you want to be able to fetch the underlying conditions scope generated by ActiveRecord. You must do this:

Property.scoped(:conditions => "foo = 2").scoped(:conditions => "foo2 IS NOT NULL").scope(:find)
# => {:conditions => "(foo = 2) AND (foo2...