Nepal on Rails

millisami's rants!

Revisited: Rails 3.1.x With Compass, Sass and Twitter-bootstrap Using the Asset Pipeline

This is a revised post for the previously released post Rails3.1 with compass, sass and twitter-bootstrap using the asset pipeline It had problems while compiling the assets via rake assets:compile

Here I’ll show you 2 alternative ways to get Compass, SASS(.sass) and Twitter bootstrap installed and compiled in a Rails 3.1.3(latest on as of writing this).

1. Using anjlab-bootstrap-rails

Add the necessary gems in the Gemfile.

group :assets do
  ...
  gem compass, :git => https://github.com/chriseppstein/compass.git, :tag => v0.12.alpha.2
  gem sass-rails, "  ~> 3.1.0"
  gem anjlab-bootstrap-rails, :require => bootstrap-rails,
                                  :git => git://github.com/anjlab/bootstrap-rails.git,
                                  :ref => eab5c9e3db95
end

Rename the app/assets/stylesheets/application.css file to app/assets/stylesheets/application.css.scss and replace the commented manifest with below.

@import "bootstrap";
@import "compass/css3";
@import "base";

The above imports all the stylesheets of Bootstrap, Compass’s CSS3 mixins and our own base.sass files.

The following is the sample base.sass file using compass/css3 mixins.

a
  outline: 0
object, embed
  outline: 0
input::-moz-focus-inner
  border: 0

div#main
  +box-shadow(red 2px 2px 10px)

We can use all the compass cross-browser compatible awesome mixins.

2. Using compass_twitter_bootstrap

Add the necessary gems in the Gemfile.

group :assets do
  ...
  gem compass, :git => https://github.com/chriseppstein/compass.git, :tag => v0.12.alpha.2
  gem sass-rails, "  ~> 3.1.0"
  gem compass-twitter-bootstrap, :git => git://github.com/vwall/compass-twitter-bootstrap.git,
                                :ref => b6f9b467bc

end

Add a file at config/initializers/sass.rb with the following:

Rails.configuration.sass.tap do |config|
  # twitter bootstrap
  config.load_paths << Compass::Frameworks[compass].stylesheets_directory
  config.load_paths << Compass::Frameworks[twitter_bootstrap].stylesheets_directory
end

Rename the app/assets/stylesheets/application.css file to app/assets/stylesheets/application.css.scss and replace the commented manifest with below.

@import "compass_twitter_bootstrap"
@import "compass/css3";
@import "base";

Verifying the assets:compile task

Well, if the bootstrap with compass works in development mode doesn’t mean that it will compile the assets properly. To verify it, the rake assets:compile task should run successfully both in development and production environment.

So, to verify this, just run

RAILS_ENV=development bundle exec rake assets:compile
RAILS_ENV=production bundle exec rake assets:compile

This should create compressed assets at public/assets directory.

Hope you find it useful.

How to Manage Multiple Chef Servers Chef Client?

I was stupid enough on how to manage multiple chef clients for multiple chef servers.

e.g.

I played with Opscode hosted chef servers. Actually, I was astonished with chef through those guys presentations/talks. And later I installed one local chef-server to play around.

But I was always confused on what are the files do I need to change while switching to the previous or another one. Should I keep them(3 files; client key, organization validator key and knife.rb) in ~/chef or ~/.chef or ~/other_folder/.chef.

But, today I find this approach simple and simple.

Do cd inside any folder that you’re managing for different servers. Make one directory named .chef and put your client key, orgnization validator kye, knife.rb

Now when you run any knife -h commands being inside that folder, the configuration will be read first from the .chef directory.

It made me much simpler, should have known before!!

Rvm Install Ruby Woes!!

Sometime when upgrading RVM or just doing a fresh install and try to install Rubies, one might stumble upon a weird problem. I’ve also encountered such situations several times. Specially, when RVM brings breaking changes while updating. The following is the most recurring issue I’ve faced with. So, just documenting for this time so that I don’t have to Google it again.

rvm install ree
ruby-1.8.7-p330 - #fetching
ruby-1.8.7-p330 - #extracting ruby-1.8.7-p330 to /Users/andrew/.rvm/src/ruby-1.8.7-p330
ruby-1.8.7-p330 - #extracted to /Users/andrew/.rvm/src/ruby-1.8.7-p330
ruby-1.8.7-p330 - #configuring
ruby-1.8.7-p330 - #compiling
Error running make , please read /Users/andrew/.rvm/log/ruby-1.8.7-p330/make.log
There has been an error while running make. Halting the installation.

If you do it again, you’ll see the error

Installing Ruby Enterprise Edition from source to: /Users/millisami/.rvm/rubies/ree-1.8.7-2011.03
It appears that the archive has already been extracted. Skipping extract (use --force to force re-download and extract).
ree-1.8.7-2011.03 - #installing
ERROR: Error running ./installer -a /Users/millisami/.rvm/rubies/ree-1.8.7-2011.03  --no-tcmalloc --dont-install-useful-gems -c --with-readline-dir=/usr/local/Cellar/readline/6.2.1, please read /Users/millisami/.rvm/log/ree-1.8.7-2011.03/install.log
ERROR: There has been an error while trying to run the ree installer. Halting the installation.

When you see the log file, you’ll see something at the end of that file:

...
readline.c: In function ‘username_completion_proc_call’
...

This error is due to the readline library.

Now you’ve got 2 options. One is to install readline via rvm pkg install readline or if you have homebrew installed, you can install it via brew update; brew install readline.

Then, brew info readline will show the readline path.

So now, you opt for either way.

# if you go via homebrew way
$ rvm remove ree
$ rvm install ree -C --with-readline-dir=/usr/local/Cellar/readline/6.2.1

# if with rvm way
$ rvm get head; rvm reload
$ rvm pkg install readline
$ rvm remove ree
$ rvm install ree --with-readline-dir=$rvm_path/usr

Tada!.

Cache Sweeper in Rails3.1, if Not Using ActiveRecord!

If you’re using Rails 3.1 but without ActiveRecord, then you cannot use the the expire_page, expire_action and expire_fragment in your controller. This might happen if you use ODMs such as Mongoid. The app that I’m working on uses Mongoid.

So, the work-around is to add a Mongoid::Observer and expire those caches by creating an instance of the ActionController::Base and call those methods on that object.

class LineObserver < Mongoid::Observer
 observe :line

 def after_save(line)
   expire_cache(line)
 end

 def after_destroy(line)
   expire_cache(line)
 end

 private
   def expire_cache(line)
     @cont ||= ActionController::Base.new
     @cont.expire_fragment "department_lines" if line.public?
   end
end

Hope this saves someone’s time.

Build Your Own Vagrant Box Ready to Use With Chef-solo Using Veewee

This is my first screencast and its a bit glitchy. The voice is not good because I’d to use the built-in microphone of my MacBook pro. I’ve to get a good one. So bare with me and the audio.

Things to shop

Assumptions

  • You know what is Virtual Box and Vagrant
  • You are familiar with Git and Github
  • You use Bundler and RVM

Building a brand new box using Ubuntu 11.10 32-bit iso image

Visit https://github.com/jedi4ever/veewee and Fork the repo under your account

Git clone git clone git://github.com/millisami/veewee cd veewee

Bundle install (if you don’t have Bundler installed, do gem install bundler --pre)

millisami at sachin in ~/gitcodes/veewee on master
± bundle install
Fetching gem metadata from [http://rubygems.org/.......](http://rubygems.org/.......)
Using Platform (0.4.0)
Using archive-tar-minitar (0.5.2)
...
Using bundler (1.1.rc)
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
millisami at sachin in ~/gitcodes/veewee on master

Gems required

gem install vagrant
gem install veewee

Define a basebox template

First, lets see what are the templates available.

millisami at sachin in ~/gitcodes/veewee on master
± bundle exec vagrant basebox templates
The following templates are available:
...
vagrant basebox define <boxname> ubuntu-10.10-server-i386-netboot
vagrant basebox define <boxname> ubuntu-11.04-server-amd64
vagrant basebox define <boxname> ubuntu-11.04-server-i386
...

So, the ubuntu 11.10 has not been defined yet. Lets build one based off the ubuntu-11.04-server-i386

millisami at sachin in ~/gitcodes/veewee on master
± bundle exec vagrant basebox define milli-ubuntu-11-10-32-bit ubuntu-11.04-server-i386
The basebox milli-ubuntu-11-10-32-bit has been successfully created from the template ubuntu-11.04-server-i386
You can now edit the definition files stored in definitions/milli-ubuntu-11-10-32-bit
or build the box with:
vagrant basebox build milli-ubuntu-11-10-32-bit

Lets see the structure of the generated folder

millisami at sachin in ~/gitcodes/veewee on master
± tree definitions
definitions
└── milli-ubuntu-11-10-32-bit
    ├── definition.rb
    ├── postinstall.sh
    └── preseed.cfg

1 directory, 3 files

Open up the folder in your editor

Open up the file definition.rb and change the version numbers from 11.04 to 11.10

# definition.rb
Veewee::Session.declare({
  :cpu_count => 1, :memory_size=> 384,
  :disk_size => 10140, :disk_format => VDI, :hostiocache => off,
  :os_type_id => Ubuntu,
  :iso_file => "ubuntu-11.10-server-i386.iso",
  :iso_src => "http://releases.ubuntu.com/11.10/ubuntu-11.10-server-i386.iso",
  :iso_md5 => "881d188cb1ca5fb18e3d9132275dceda",
  :iso_download_timeout => "1000",
  :boot_wait => "10", :boot_cmd_sequence => [
    <Esc><Esc><Enter>,
    /install/vmlinuz noapic preseed/url=http://%IP%:%PORT%/preseed.cfg ,
    debian-installer=en_US auto locale=en_US kbd-chooser/method=us ,
    hostname=%NAME% ,
    fb=false debconf/frontend=noninteractive ,
    keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false ,
    initrd=/install/initrd.gz -- <Enter>
  ],
  :kickstart_port => "7122", :kickstart_timeout => "10000", :kickstart_file => "preseed.cfg",
  :ssh_login_timeout => "10000", :ssh_user => "vagrant", :ssh_password => "vagrant", :ssh_key => "",
  :ssh_host_port => "7222", :ssh_guest_port => "22",
  :sudo_cmd => "echo %p|sudo -S sh %f",
  :shutdown_cmd => "shutdown -P now",
  :postinstall_files => [ "postinstall.sh"], :postinstall_timeout => "10000"
})

Open up the file postinstall.sh and change libreadline5-dev to libreadline5 because the Ubuntu Oneiric doesn’t have libreadline5-dev package.

millisami at sachin in ~/gitcodes/veewee on master
± be vagrant basebox build milli-ubuntu-11-10-32-bit

Setup GitLab (Github Clone) Using Vagrant and Chef

Update: Nov 28, 2011: The box that is downloaded via vagrant might not work properly. Here is the box that I’d custom built to have chef pre-installed. You can download it here http://api2.ge.tt/0/8gA4QSA/0/blob/download

This post is Part 1 of the series Rails app with distributed deployment playground

Here we’ll be installing GitlabHQ.

I won’t be showing on how to install Vagrant with VirtualBox here. If you’re not familiar with Vagrant and how to set it up, then first watch the Railscasts 292 and install the Vagrant with VirtualBox.

Then you can start with the following commands in the terminal. First of all, we have to have our own chef-repo to contain the cookbooks.

You can clone my repo or you can use your own or others. Here I’ll be using mine chef-repo

cd
git clone git://github.com/millisami/chef-repo.git

Now, lets start with the gitlabhq setup.

cd
mkdir vagrants
cd vagrants
git clone git://github.com/gitlabhq/gitlabhq.git
cd gitlabhq
vagrant init

Modify the Vagrantfile as below

Vagrant::Config.run do |config|
  config.vm.box = "lucid32"
  config.vm.network "33.33.33.20"

  config.vm.customize do |vm|
    vm.name = "GitlabHQ"
    vm.memory_size = 384
  end

  config.vm.provision :chef_solo do |chef|
    chef.log_level = :debug
    chef.cookbooks_path = ["~/chef-repo/cookbooks"]
    chef.add_recipe "base"
    chef.add_recipe "rvm::install"
    chef.add_recipe "rvm::ruby_192"

    chef.json = {
      :base => {
        :system_packages => ["tree", "htop", "vim-nox"]
        }
      }
    }
  end
end

Then from the terminal, run the following commands.

vagrant up
vagrant ssh

Once you login, install these dependencies.

sudo apt-get install -y git-core sqlite3 libsqlite3-dev gitosis libcurl4-openssl-dev python-setuptools

sudo visudo

Add the following line at the VERY BOTTOM of the file, if not at the end, it can be nullified by later entries

vagrant ALL=(ALL) NOPASSWD: ALL

Ctrl-X to leave, Y to save your changes. Logout logout and ssh vagrant ssh again to reflect the effect.

Lets install the gem dependencies.

cd /vagrant
rvmsudo gem install bundler --pre
bundle

# Seeding the database
RAILS_ENV=production bundle exec rake db:setup
RAILS_ENV=production bundle exec rake db:seed_fu

Write the admin account and its password which we’ve to use later while accessing gitlab.

...
Administrator account created:

login.........admin@local.host
password......5iveL!fe

Then, we have to setup the following:

sudo easy_install pygments
sudo echo export RAILS_ENV=production >> ~/.bash_profile
sudo adduser --system --shell /bin/sh --gecos git version control --group --disabled-password --home /home/git git
ssh-keygen -t rsa
sudo -H -u git gitosis-init < ~/.ssh/id_rsa.pub
sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update

echo "gem: --no-rdoc --no-ri" > ~/.gemrc
rvmsudo gem install passenger
rvmsudo passenger-install-nginx-module

Creating an Upstart file for nginx

sudo vim /etc/init/nginx.conf

description "Nginx HTTP Server"

start on filesystem
stop on runlevel [!2345]

respawn

exec /opt/nginx/sbin/nginx -g "daemon off;"

Restart the VM

sudo shutdown -r now

Verify nginx urnning

sudo initctl list | grep nginx

You should see:

nginx start/running, process 678

…Or use a browser and visit http://33.33.33.20

Open nginx.conf to configure nginx

sudo vim /opt/nginx/conf/nginx.conf

Change the user to ‘vagrant’

Then inside the http {....}, add/replace a server block looking similar to this:

...
http {
  ...

    server {
    listen 80;
    server_name localhost;
    root /vagrant/public;
    passenger_enabled on;
    }
    ...
}

Restart nginx to pick up the changes

sudo service nginx stop; sudo service nginx start

or just

sudo start|stop nginx

Setting up the first repository

  1. Access [http://33.33.33.20](http://33.33.33.20) on the HOST machine’s browser
  2. Login in using admin@local.host and 5iveL!fe
  3. Add your HOST key at [http://33.33.33.20/keys](http://33.33.33.20/keys)
  4. Create the first project, say (Myproject)
  5. Add a remote. git remote add vagrant-chef git@33.33.33.20:Myproject.git
  6. Push with tracking branch. git push -u vagrant-chef master

Dealing with the Git and SSH keys gotchas

  1. Added user vagrant to group git since /home/git/repositories directory is owned by git

  2. Did one clone in ~/tmp directory git clone git@localhost:gitosis-admin.git gitosis-copy to add the RSA key to the list of known hosts. So, that when later via browser, the webserver will try to create a new repo. Otherwise you might end up with the infamous 500 error page.

Thats it for this part. Hang-on for the part 2 of the series Rails app with distributed deployment playground

Rails App With Distributed Deployment Playground

While setting up Etxpress on the production box with system wide installed RVM and Resque for background processing, monitored via Upstart using Foreman export command, I had to run the following command to export the updated Procfile.production file with capistrano and custom cap deploy:foreman task.

rvmsudo foreman export upstart /etc/init -a etxpress -u deploy \
        -f ./Procfile.production -c worker=1 scheduler=1 redis=1

Since the command rvmsudo is for sudoers, it asks for sudo password which capistrano cannot handle. Similarly, there are some other commands that need the sudo access as well. So, tweaking the settings directly in production and playing with cap deploy:foreman and other sudo related tasks, I’d to manually login and do service restarts.

This is not a best practice to test or play with deployment settings directly on the production box. So, to simulate the same environment and process, here the Vagrant and Chef come in.

The idea is to host a Gitlab as a Github repo in one VM, launch another VM to simulate the production box and setup the multistage capistrano recipe to test and experiment.

Local Deployment Diagram

It will be a long post. So, I’ll be blogging in the following series:

  1. Setup Gitlab as a Github repo hosting
  2. Setup a production box in another VM
  3. Setup capistrano multistage to test the deployment

To automate the process, we’ll be using vagrant to launch VM(s) and chef-solo for provisioning. I might do another post using chef-server to make it more automated.

Without further ado, here is the first part of the series: Setup Gitlab as a Github repo hosting using vagrant and chef-solo.

Installing Ruby-debug in Ruby 1.9.3 With Rvm

blog.wyeworks.com posted a way to install ruby-debug in 1.9.3 in rbenv addressing the details of the problem.

I’m just posting a quick installation in rvm. Install ruby 1.9.3 if you haven’t or skip to the next block.

rvm get head
rvm install ruby-1.9.3-p0
rvm reload
rvm 1.9.3

Now lets install the ruby-debug gem. Follow the below simple steps:

cd ~/tmp
wget [http://rubyforge.org/frs/download.php/75414/linecache19-0.5.13.gem](http://rubyforge.org/frs/download.php/75414/linecache19-0.5.13.gem)
wget [http://rubyforge.org/frs/download.php/75415/ruby-debug-base19-0.11.26.gem](http://rubyforge.org/frs/download.php/75415/ruby-debug-base19-0.11.26.gem)

$ gem install linecache19-0.5.13.gem
Building native extensions.  This could take a while...
Successfully installed linecache19-0.5.13
1 gem installed
$ gem install ruby-debug-base19-0.11.26.gem -- --with-ruby-include=$rvm_path/src/ruby-1.9.3-p0
Building native extensions.  This could take a while...
Successfully installed ruby-debug-base19-0.11.26
1 gem installed
$ irb
irb(main):001:0> require ruby-debug
=> true

Installing Ruby-debug19 With Rvm or Just Normal Ruby Installed

While installing ruby-debug19 whether with rvm or normal ruby installation, I often trip into the following error while through bundle install or just gem install ruby-debug19

Installing linecache19 (0.5.12) with native extensions
Unfortunately, a fatal error has occurred. Please report this
error to the Bundler issue tracker at
[https://github.com/carlhuda/bundler/issues](https://github.com/carlhuda/bundler/issues) so that we can fix
it. Thanks!

/Users/millisami/.rvm/rubies/ruby-1.9.2-head/lib/ruby/site_ruby/1.9 .1/rubygems/installer.rb:552:in `rescue in block in build_extensions’: ERROR: Failed to build gem native extension. (Gem::Installer::ExtensionBuildError)

        /Users/millisami/.rvm/rubies/ruby-1.9.2-head/bin/ruby extconf.rb
checking for vm_core.h... no
checking for vm_core.h... no
.......
.......
.......

So, this is just a note to myself not to google again and again if I trip into this error again. So, the solution is just gem install ruby-debug19 -- --with-ruby-include=$rvm_path/src/ruby-1.9.2-head/

gem install ruby-debug19 -- --with-ruby-include=$rvm_path/src/ruby-1.9.2-head/
Building native extensions.  This could take a while...
Fetching: ruby-debug-base19-0.11.25.gem (100%)
Building native extensions.  This could take a while...
Fetching: ruby-debug19-0.11.6.gem (100%)
Successfully installed linecache19-0.5.12
Successfully installed ruby-debug-base19-0.11.25
Successfully installed ruby-debug19-0.11.6
3 gems installed

If you’re using rvm, don’t forget to replace the <ruby-1.9.2-head> with your choice of ruby.

This also works for non-rvm installs, just chage the —with-ruby-include= value to point to an extracted copy of the source.

Rails3.1 With Compass, Sass and Twitter-bootstrap Using the Asset Pipeline

I prefer the sass original syntax over the new scss. And I don’t want to loose the awesome CSS3 mixins. When you google, you’ll find many articles and almost all have different hacks to implement. But as of today, those load paths hacks are not necessary when I tried to use the compass and twitter-bootstrap.

Add the necessary gems in the Gemfile.

group :assets do
  ...
  gem compass, git: https://github.com/chriseppstein/compass.git
  gem sass-rails, "  ~> 3.1.0"
  gem anjlab-bootstrap-rails, :require => bootstrap-rails,
                                :git => git://github.com/anjlab/bootstrap-rails.git
end

Rename the app/assets/stylesheets/application.css file to app/assets/stylesheets/application.sass and change the commented manifest from:

/*
 * This is a manifest file thatll automatically include all the stylesheets available in this directory
 * and any sub-directories. Youre free to add application-wide styles to this file and theyll appear at
 * the top of the compiled file, but its generally better to create a new file per style scope.
 *= require_self
 *= require_tree .
*/

to sass comment style

// * This is a manifest file thatll automatically include all the stylesheets available in this directory
// * and any sub-directories. Youre free to add application-wide styles to this file and theyll appear at
// * the top of the compiled file, but its generally better to create a new file per style scope.
// *= require_self
// *= require_tree .
// *= require bootstrap

Now do import of compass css3 mixins the sass way in the same application.sass file or other files.

@import "compass/css3/opacity"

#logo h1
  +opacity(0.5)

Thats it.