Rails tips

Found these on HabraHabr today. Here are some tricks I found usefull.

Private methods are not actually private

Let us have class:

class Moo
  private

  def self.foo
    puts 'foo'
  end
end

Here, class method foo is not private:

Foo.foo
=> 'foo'

Instance with params

Oftenly there is a need to create a class instance and set it some params (or, maybe, call some methods on it). It’s done usually like this:

moo = Moo.new
moo.foo = 'foo'
moo.bar

This can be shortened with the use of `tap` method:

moo = Moo.new.tap { |a| a.foo = 'foo'; a.bar }

Yet, it is more ruby-convenient and ruby-style to do it with the initialization block:

class Moo
  attr_accessor :foo

  def initialize(&block)
    yield self if block_given?
  end

  def bar
    puts "bar!"
  end
end

moo = Moo.new do |a|
  a.foo = 'foo'
  a.bar
end

puts moo.foo

Or even like this:

class Moo
  def initialize(&block)
    instance_eval &block if block_given?
  end

  def moo(val = nil)
    @moo = val unless val.nil?
    @moo
  end

  def bar
    puts "bar!"
  end
end

a = Moo.new do
  moo 'moo~!'
  bar
end

puts a.moo

Code-dependent migrations

When you have your migrations using your code, for example, like this:

class CreateDataVolumes < ActiveRecord::Migration
  def up
    Data::VOLUMES.times do |volume|
      create_table "data_#{volume}" do |t|
        # ...
      end
    end
  end
end

you then have a problem when updating your code. In our example, if you remove the constant Data::VOLUMES, you will have to either manually search for all the usages of this constant, or have a really intelliJent IDE ;)

Rather than using your existing code, stub it and copy-and-paste all migration-dependent code to the stubbing class:

class CreateDataVolumes < ActiveRecord::Migration
  class Data < AR::Base
    VOLUMES
  end

  def up
    Data::VOLUMES.times do |volume|
      # ...
    end
  end
end

Example with constant is rather stupid, whilst you may have some more critical code.