Sunday, December 12, 2010

Mongoid: autocreate_indexes

Indexes help make your database reads faster, but has the downside of making your database writes slower. Either way, you will come across the need for indexes at some point.

Mongoid has a flag called autocreate_indexes. This flag tells MongoDB to create the indexes every time a class is loaded. This is set to false by default. However, when you add an index to a model, your application will complain since there is no index in MongoDB yet.

To get around this, you can set autocreate_indexes to true. You only want to do this for development and test since this can be slow. For staging and production, you will need to log into MongoDB and create an index manually before pushing your code.

Thursday, November 18, 2010

RSpec 2: #raise_error

I was writing a spec and attempted to use #raise_error. To my surprise, it wasn't working. Here's what I did and how I solved it.

Code to be tested:
class TestClass
  def run; raise "Error"; end
end

Spec:
it 'should raise' do
  TestClass.new.run.should raise_error
end

To my surprise, the error wasn't caught and it failed with a raised error. There was no syntax error and the way I wrote it felt very natural, but it wasn't behaving the way I thought it should. However, upon further investigation, I realized the usage of #raise_error is on a Proc or lambda.

The spec should have been:
it 'should raise' do
  Proc.new { TestCase.new.run }.should raise_error
  lambda { TestCase.new.run }.should raise_error
end

And if you really want it to read well:
it 'should raise' do
  expect { TestCase.new.run }.to raise_error
end

Thursday, November 11, 2010

Fixing Ruby on Ubuntu

Before using RVM, I was using the default Ruby installation on Ubuntu. Then, I needed different versions of Ruby and started messing around with installing other Rubies. Apparently, I messed up my default Ruby install without knowing it. Then, I moved off to RVM and never looked back.

Recently, I needed my system Ruby again. This is when I found out it was completely messed. It kept giving me this error when I tried to use RubyGems.
'require': no such file to load -- thread (LoadError)

This was supposed to be impossible since thread is in the core library of Ruby. Then, I tried other things like requiring pp and date. Both gave me the same error.

I attempted to reinstall Ruby.
sudo apt-get purge ruby ruby-dev ruby1.8 ruby1.8-dev rubygems rubygems1.8
sudo apt-get install ruby ruby-dev rubygems

Unfortunately, this didn't help at all. I tried this several times to no avail. I then tried installing RubyGems through the source, but I couldn't even run setup.rb since it requires core libraries.

I decided to look through Synaptic Package Manager for anything that matched Ruby. That's when I realized I hadn't uninstalled all of Ruby. I had missed the Ruby libraries! Duh! I had messed up my Ruby libraries and wasn't reinstalling it.
sudo apt-get purge libruby libruby1.8
sudo apt-get install libruby

This fixed my require problems and all was right again.

Friday, November 5, 2010

Brother HL-2170W: Installation Gotchas + Reset to Factory Settings

Using Ubuntu 10.04, I decided to install this brand new printer and enable wireless printing. If you are using a USB cable, just plug-and-play. It just works. If you are planning to use wireless, read on!

Network Cable

You will need an extra network cable if your computer doesn't have wireless.

Wireless Authentication

The first gotcha is wireless authentication. This printer seems to behave properly only with AES encryption. TKIP will not work. Go ahead and change your settings from your router. I'll wait.

Wireless Setup

Get hold of a Windows or Mac machine. You NEED this in order to setup wireless. Ubuntu does not have an interface to this part of the printer. Unfortunately, you will need the CDs that come with the printer as well. Plop the CD into your computer and run it. A wizard will show up. It's pretty straightforward until you get to the "Top Menu". Here, you need to click the following:
  1. Install Printer Driver (even though we just want to setup wireless)
  2. Wireless Network users (window pops up)
  3. Wireless Setup Only
  4. Step by Step install
From here, follow the rest of the wizard. It should detect your printer and allow you to configure settings such as IP address (if you decided to use static IP) and wireless authentication. Fill it all in. At the end, it will tell you to unplug the network cable from the printer and ask if you want to print the settings. Make sure you print the settings. If anything goes wrong, it tells you on the print-out. When I wasn't using AES encryption, I had "Failed To Associate" under "Wireless Link Status".

MAC Addresses

If you do anything with MAC addresses, the second gotcha is that the wired interface and the wireless interface have different MAC addresses. Be careful that you use the wireless one.

Ubuntu

Time to add the printer! Go to System > Administration > Printing > Add. Wait for a little bit. The New Printer popup should automatically detect your printer. Here's the third gotcha. I saw two. One that said "LPD network printer via DNS-SD" and one where it asked for Host (Probe) and Queue. You must select the DNS-SD one. The other one doesn't work! After selecting DNS-SD, it should look for drivers and then ask to print a test page. Make sure the test page prints.

Done!

Reset to Factory Settings

In case you screw up the settings and can't access the printer anymore, you can reset it to factory settings.
  1. Turn off the printer using the switch on the side.
  2. While holding down the Go button (big button that lights up blue in the corner), turn the switch on.
  3. Hold the Go button until the Toner, Drum, and Error lights turn on (this may be immediate).
  4. Let go of the Go button.
  5. Wait for the Toner, Drum, and Error lights to turn off (this may be immediate).
  6. Press the Go button 7 times. 
  7. The Toner, Drum, and Error lights should light up after the 7th time. This means the printer has been reset to factory settings.

Monday, October 25, 2010

Rails 3.0: MongoDB + Mongoid

Why Mongoid?

The de facto ORM for MongoDB in Rails is Mongo Mapper, so why choose Mongoid? You can ready why straight from the horses mouth here.

To summarize, Mongoid is built for Rails 3.0 and it handles larger documents better. It also feels like NoSQL when you use it. MongoMapper was built during Rails 2.x days and when MongoDB was young. It is modeled very closely to ActiveRecord to make the transition easier. Hence, it feels more like SQL. MongoMapper is more extensible though with a larger community.

MongoDB

Grab the latest build from MongoDB's download page. At this time, it is 1.6.3.

Download and install. We make a softlink. This way, if we upgrade, we just switch the softlink and everything else stays the same.
cd /usr/local/src/
sudo wget http://fastdl.mongodb.org/linux/mongodb-linux-i686-1.6.3.tgz
sudo tar xzf mongodb-linux-i686-1.6.3.tgz
sudo rm -rf mongodb-linux-i686-1.6.3.tgz
sudo ln -s mongodb-linux-i686-1.6.3 mongodb

Add /usr/local/src/mongodb/bin to your path.
PATH=$PATH:/usr/local/src/mongodb/bin

Make /data/db and give ownership to your user. There are obviously several ways to do this, but this is the easiest.
sudo mkdir -p /data/db
sudo chown -R wesley:wesley /data

Start your engines!
mongod

Mongoid

This builds on top of my previous post on installing Rails 3.0 with BDD. This assumes that the Rails application was created without ActiveRecord using -O. Check out Rails 3.0 agnosticism for an explanation.

Add mongoid to Gemfile. bson_ext is installed for a speed boost.
gem 'mongoid', '2.0.0.rc.6'
gem 'bson_ext', '~>1.2'

Install mongoid.
bundle install
rails generate mongoid:config

Cucumber

Add a cucumber environment to mongoid.yml.
cucumber:
  <<: *defaults
  database: myproject_cucumber 

Cucumber makes use of Database Cleaner. There are posts saying Database Cleaner doesn't work with Mongoid. However, it seems like it is now according to the official documentation. We need to modify features/support/env.rb this is not recommended as it is regenerated on a cucumber-rails upgrade. Instead, we will create features/support/local_env.rb.
require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.orm = "mongoid"
Before { DatabaseCleaner.clean }

RSpec 2

RSpec includes ActiveRecord specific lines in spec/spec_helper.rb. You need to comment out the following 2 lines.
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# config.use_transactional_fixtures = true

To properly clean the database, RSpec needs to know how to do that with Mongoid. Again, we can use Database Cleaner for this.

Open up spec/spec_helper.rb and add the following in the RSpec.configure block
RSpec.configure do |config|    
  # Other things

  # Clean up the database      
  require 'database_cleaner'   
  config.before(:suite) do     
    DatabaseCleaner.strategy = :truncation
    DatabaseCleaner.orm = "mongoid" 
  end

  config.before(:each) do
    DatabaseCleaner.clean      
  end
end 

References


Updates

December 2, 2010: Changed Cucumber local_env.rb for database cleaning.
December 2, 2010: Added a section for RSpec database cleaning.
February 1, 2011: Updated Mongoid version in the Gemfile
February 26, 2011: Added a note to clean out ActiveRecord specific lines in RSpec.

Tuesday, October 19, 2010

Rails 3.0: Installing Cucumber + RSpec 2 + Capybara + AutoTest

Behaviour Driven Development (BDD) was created in response to Test Driven Development (TDD). TDD had brought the idea of testing to the forefront, but stopped short when it was applied mainly to developers. It failed to include other stakeholders. BDD is suppose to remedy this by specifying the behaviour of the application at a high level in English. This allows non-developers to spec out the application and be included in the conversation.

Cucumber

Cucumber is a BDD framework for Ruby. Specs will be written at this higher layer first to drive behaviour.

RSpec 2

RSpec 2 just came out of beta. It is a TDD framework for Ruby. Specs will be written at this second layer for testing the details of the implementation.

Capybara

Capybara is a replacement for Webrat. It is used to simulate how a real world user would interact with your application. A good post about why you would use Capybara over Webrat can be found here.

AutoTest

AutoTest runs your Cucumber and RSpec specs automatically whenever a file that affects the specs is modified.

Install

This builds on top of my previous post on installing Rails 3.0. This assumes that the Rails application was created without Test::Unit using -T. Check out Rails 3.0 agnosticism for an explanation.

Open Gemfile and add the following.
group :development, :test do
  gem 'capybara'
  gem 'database_cleaner'
  gem 'cucumber-rails'
  gem 'cucumber'
  gem 'rspec-rails'
  gem 'autotest'
  gem 'spork'
  gem 'launchy'
end

Install the gems. If you aren't using ActiveRecord, you won't have a database.yml. cucumber:install will complain unless you pass -D to it.
bundle install
rails generate rspec:install
rails generate cucumber:install --rspec --cabybara

AutoTest checks your entire project for changes. When tests fail, test.log is written to and because there is a change, AutoTest will kick-off again, and again, and again. To stop this from happening, create a .autotest at the root of your project to ignore certain files.
Autotest.add_hook :initialize do |at|                                                                                                                                                                          
  %w{ .git doc log tmp vendor }.each { |ex| at.add_exception( ex ) } 
end

AutoTest does not run Cucumber out of the box. There is debate whether autotesting Cucumber is a good idea since it is a very high-level test and can be quite heavy. Autotests should run quickly. If you want autotesting of Cucumber, you must add AUTOFEATURE to your environment before running or in your .bashrc.
export AUTOFEATURE=true

Start continuous testing. Hit ctrl+c twice to stop.
autotest

References


Updates

Feb. 8, 2011: Added solution to AutoTest continuously running on failure.

Monday, October 18, 2010

Rails 3.0: Agnosticism

When Rails and Merb merged, agnosticism was one of the big features to be added to Rails. They have stayed true to this vision.

Take a look at the help when creating a new Rails application.
rails new --help

You will notice three options.
  • -O: Skip Active Record
  • -T: Skip Test::Unit
  • -J: Skip Prototype

This allows you to create a fresh Rails application and have it ready to integrate with other gems more easily.
rails new myproject -OTJ