Dimitar Kostov ramblings

Integer types in Rails

By default Rails will create INT(11) for integer type without limit. If you want to use different integer type like BIGINT you should use :limit.

1
2
3
4
5
6
7
8
9
+------------------------------------------------------------+
| :limit | Numeric Type  | Column Size |      Max Value      |
|--------+---------------+-------------+---------------------|
|    1   |    TINYINT    |   1 byte    | 127                 |
|    2   |    SMALLINT   |   2 bytes   | 32767               |
|    3   |    MEDIUMINT  |   3 bytes   | 8388607             |
|    4   |     INT(11)   |   4 bytes   | 2147483647          |
|    8   |     BIGINT    |   8 bytes   | 9223372036854775807 |
+------------------------------------------------------------+

Example in a migration file:

1
add_column :users, :amount, :integer, limit: 8 # BIGINT
Notice: If you don’t supply limit it defaults to 4 => INT(11). If your limit is 5..8 it will be BIGINT

Test autocomplete in Rails

Easy way to test autocomplete in RSpec request spec with Capybara

1
2
3
4
5
6
7
8
9
describe 'Description of the spec'
  it "should autocomplete user name", js: true do
    visit users_path
    auto_complete_field = 'user_name'
    fill_in auto_complete_field, with: 'Dimitar'
    page.execute_script %Q{ $('##{auto_complete_field}').trigger("keydown") }
    page.should have_content('Dimitar Kostov')
  end
end
Notice: You should use capybara-webkit driver to enable JavaScript interaction.

Get HOME directory

1
2
3
4
5
require 'etc'

login = Etc.getlogin

config_file = File.join(Dir.home(user), ".zshrc")

Fixing Ruby build in Sublime Text 2

If youre getting this error while trying to run ruby script, just replace the loop in Packages/Default/exec.py on line 44 with the snippet below:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 60 ...
Packages/Default/exec.py:44
1
2
3
4
5
for k, v in proc_env.iteritems():
  path_vars = os.path.expandvars(v)
  if isinstance(path_vars, unicode):
      path_vars = path_vars.encode(sys.getfilesystemencoding())
  proc_env[k] = path_vars

Janky setup: Jenkins, Hubot, HipChat and Ruby

Prerequisites

Jenkins installation and setup

First of all, you need box to deploy Jenkins server. I would recommend DigitalOcean, because they provide awesome service at really low cost. Here we go:

$ ssh root@111.222.333.444
~# wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | apt-key add -
~# sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
~# apt-get update
~# apt-get install jenkins

Change newly created jenkins user password:

~# passwd jenkins

Add jenkins to the sudoers (not necessary):

~# visdudo

jenkins ALL=(ALL:ALL) ALL

Allow jenkins to connect through ssh and disable root login

~# nano /etc/ssh/sshd_config

AllowUsers jenkins
PermitRootLogin no

~# reload ssh

Upload your ssh key for login without password:

$ scp ~/.ssh/id_rsa.pub jenkins@111.222.333.444:/var/lib/jenkins/.ssh/authorized_keys

Navigate to your server on port 8080 and install necessary plugins:

  1. Click on ‘Manage Jenkins’
  2. Click on ‘Manage Plugins’
  3. Click on ‘Available’ tab
  4. Check ‘rbenv’ and ‘Notification Plugin’ and click ‘Install without restart’

Install rbenv and ruby-build:

$ sudo apt-get -y install build-essential zlib1g-dev libssl-dev\
libreadline-dev libyaml-dev libcurl4-openssl-dev curl git-core python-software-properties
$ git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l
$ rbenv install 2.0.0-p0
$ rbenv global 2.0.0-p0
$ rbenv rehash
$ gem install bundler

Janky installation and setup

$ git clone git://gist.github.com/1497335 janky
$ cd janky
$ heroku create --stack cedar
$ heroku rename our-janky-server
  Add require "janky/chat_service/hipchat" to config/environment.rb file before the Janky.setup(ENV)
$ echo 'gem "hipchat", "~>0.4"' >> Gemfile
$ bundle install
$ git add Gemfile.lock
$ git commit Gemfile.lock -m "lock bundle"
$ git push heroku master
$ heroku config:add JANKY_BASE_URL="http://our-janky-server.herokuapp.com/"
$ heroku config:add JANKY_BUILDER_DEFAULT="Jenkins URL"
$ heroku config:add JANKY_CONFIG_DIR="/app/config"
$ heroku config:add JANKY_HUBOT_USER="hubot"
$ heroku config:add JANKY_HUBOT_PASSWORD="hubot"
$ heroku config:add JANKY_GITHUB_USER="mytrile"
$ heroku config:add JANKY_GITHUB_PASSWORD="password"
$ heroku config:add JANKY_GITHUB_HOOK_SECRET="..."
$ heroku config:add JANKY_CHAT_DEFAULT_ROOM="room"
$ heroku config:add JANKY_CHAT=hipchat
$ heroku config:add JANKY_CHAT_HIPCHAT_TOKEN="..."

$ heroku run rake db:migrate
$ heroku ps:scale web=1

Hubot installation and setup

$ wget https://github.com/github/hubot/archive/master.zip
$ unzip master.zip
$ cd hubot-master
$ npm install
$ make package
$ cd hubot
$ wget -O scripts/janky.coffee https://raw.github.com/github/hubot-scripts/master/src/scripts/janky.coffee

Note: Remove redis-brain.coffee from hubot-script.json if you don’t to setup redis

Add hubot-hipchat dependecy to package.json:

"dependencies": {
  "hubot-hipchat": ">= 2.4.5",
  ...
}

Edit the Procfile:

web: bin/hubot --adapter hipchat -n Hubot

Deploy Hubot:

$ git init
$ git add .
$ git commit -m 'initial commit'
$ heroku create
$ heroku rename our-company-hubot
$ heroku config:add HEROKU_URL=http://our-company-hubot.herokuapp.com

Create account for your HipChat bot and configure it:

$ heroku config:add HUBOT_HIPCHAT_JID="12345_678901@chat.hipchat.com"
$ heroku config:add HUBOT_HIPCHAT_PASSWORD="mypassword"
$ heroku config:add HUBOT_HIPCHAT_TOKEN="…"
$ heroku config:add HUBOT_JANKY_URL="http://hubot:hubot@our-janky-server.herokuapp.com/_hubot"
$ heroku ps:scale web=1

Note: HUBOT_HIPCHAT_TOKEN should be the admin token, not the bot user token

Usage

We’re almost there. The last to do is to tweak Jenkins after the initial setup. In the HipChat room where your bot is:

> hubot ci setup username/repo
> hubot ci build repo

There should be new job in your Jenkins server that can be configured accordingly your application.

Testing after_commit in rspec

mail_worker.rb
1
2
3
4
5
6
7
8
9
# app/workers/mail_worker.rb

class MailWorker
  include Sidekiq::Worker

  def perform(id)
    # send mail
  end
end
spec_helper.rb
1
2
3
4
5
6
7
# spec/spec_helper.rb

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  # rest of the configuration
end
user.rb
1
2
3
4
5
6
7
8
9
10
11
# app/models/user.rb

class User < ActiveRecord::Base
  after_commit :send_welcome_mail, on: create

  private

  def send_welcome_mail
    MailWorker.perform_async(self.id)
  end
end
user_spec.rb
1
2
3
4
5
6
7
8
9
10
11
# spec/models/user_spec.rb

require 'spec_helper'

describe AffiliateProgram do
  let(:user) { FactoryGirl.create(:user) }

  it "should queue sending mail for user" do
    expect { user.run_callbacks(:commit) }.to change { AffiliateProgramOfferWorker.jobs.count }.by(1)
  end
end

Easy setup for Postgres.app and Rails

This is how you setup Postgress.app with Rails

~ psql
username=# CREATE DATABASE myapp_development;
username=# \q
.zshrc
1
export PATH="/Applications/Postgres.app/Contents/MacOS/bin:$PATH"</pre>
database.yml
1
2
3
4
5
6
7
8
development:
  adapter: postgresql
  encoding: unicode
  database: myapp_development
  pool: 5
  host: localhost
  username: username
  password: