Archive for November, 2007

Tinder Continuous Integration to Campfire Script

November 30th, 2007 by pyrat

Campfire

Recently signal vs noise showcased how their continuous integration tool posts to campfire using the tinder api. Well I thought that it looked cool so have thrown together a quick and dirty ruby script to do it as well.

It will integrate with anything which has an RSS feed. Cruisecontrol.rb does and works nicely. Its a bit rough around the edges but works as is. Run it from the crontab and you are sorted.

Improvements welcome.

Here is a screenshot of it posting on campfire:

Ci Grab

Here is the code:

#!/usr/bin/ruby
 
require 'rubygems'
require 'active_record'
require 'simple-rss'
require 'open-uri'
require 'tinder'
include Tinder
 
# Author: Alastair Brunton
# http://www.simplyexcited.co.uk
# Rss to Campfire
 
campfire_domain = 'simplyexcited'
campfire_email = 'cheer@cheerfactory.co.uk'
campfire_password = 'xxxx'
feeds = %w(http://feedserver/edflats.rss)
 
 
ActiveRecord::Base.logger = Logger.new(STDERR)
ActiveRecord::Base.colorize_logging = false
 
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:username => "username",
:password => "password",
:database => "ci_to_campfire"
)
 
# uncomment this section the first time to create the table
 
# ActiveRecord::Schema.define do
#    create_table :items do |table|
#        table.column :feed_identifier, :string
#        table.column :title, :string
#        table.column :link, :string
#        table.column :description, :text
#    end
# end
 
class Item < ActiveRecord::Base
  def to_s
    %(Theres been some action:\n
    #{self.title}\n\n
    #{self.description}
    )
  end
end
 
 
campfire = Campfire.new campfire_domain
campfire.login campfire_email, campfire_password
room = campfire.find_room_by_name('The Office')
feeds.each do |rss_url|
  rss_user_agent = "RSS to Campfire"
 
  rss_items = SimpleRSS.parse open(rss_url ,"User-Agent" => rss_user_agent)
 
  for item in rss_items.items
 
    Item.transaction do
      unless existing_item = Item.find(:all, :conditions => ["link=? AND feed_identifier=?", item.link, rss_url]).first
        new_item = Item.create(:title => item.title, :link => item.link, :description => item.description, :feed_identifier => rss_url)
        room.paste(new_item.to_s)
      end
    end
  end
end
room.leave
campfire.logout

Attachment Fu Validates As Attachment Hack

November 28th, 2007 by pyrat

Attachment Fu Hack

Recent err the blog posted about the my evil twin hack technique

In this post they detail how to hack plugins nicely and provide an example on how to hack attachment_fu. It turns out that I have been spending quite a bit of time with attachment_fu on various projects recently and have started to need it to do slightly different things.

Below is a hack I have written to improve validates_as_attachment. Using the evil twin technique this will just ask for a file to be uploaded if you dont upload anything. Instead of spewing out a whole load of errors that dont help the user much.

klass = Technoweenie::AttachmentFu::ClassMethods
klass.module_eval do
 
def validates_as_attachment
validate :uploaded_data_is_present
validates_presence_of :size, :content_type, :filename, :if => :uploaded_data?
validate              :attachment_attributes_valid?
end
 
end
 
klazz = Technoweenie::AttachmentFu::InstanceMethods
klazz.module_eval do
def uploaded_data?
  return false unless filename
  true
end
 
# validates the size and content_type attributes according to the current model's options
def attachment_attributes_valid?
if uploaded_data?
[:size, :content_type].each do |attr_name|
enum = attachment_options[attr_name]
errors.add attr_name, ActiveRecord::Errors.default_error_messages[:inclusion] unless enum.nil? || enum.include?(send(attr_name))
end
end
end
 
def uploaded_data_is_present
unless uploaded_data?
errors.add_to_base("You must select a file to upload.")
end
end
 
end

This serves as a drop in replacement for validates_as_attachment

php commandline on ubuntu

November 20th, 2007 by pyrat

Tested on Ubuntu LTS 6.06

  sudo apt-get install php5-cli

Installing Nginx on Ubuntu Dapper (LTS 6.06)

November 15th, 2007 by pyrat

There is a great slicehost article which goes into more detail than this. But the following script will install it from source in one go!.

#!/bin/bash
 
sudo apt-get install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev
wget http://sysoev.ru/nginx/nginx-0.5.33.tar.gz
tar -zxvf nginx-0.5.33.tar.gz
cd nginx-0.5.33
./configure --sbin-path=/usr/local/sbin --with-http_ssl_module
make
sudo make install
cd ~
cd sources
sudo wget http://notrocketsurgery.com/files/nginx -O /etc/init.d/nginx
sudo chmod 755 /etc/init.d/nginx
sudo update-rc.d nginx defaults

2 techniques for rails testing without fixtures

November 13th, 2007 by pyrat

fixtures

After it taking me 6 months to be converted to TDD, the last 6 months I have been improving my skills in the TDD arena. After developing some fairly complex systems I was finding fixtures to be far too brittle and was relying on the ar_fixtures plugin to generate fixture data.

The thing is, this isn’t right. You shouldn’t be generating the fixtures from data created by untested code!

To get straight to the point, the following 2 techniques are great for fixture-less testing.

1. Have a phat test_helper.rb

Use transactional fixtures.

In your test_helper.rb you should be extracting out all the object creation code so you can use it over multiple tests.

eg.

  def create_property(options={})
    Property.create!(
    {
      :title => 'Flat in Skye',
      :address_line_1 => 'Flat 2/1',
      :address_line_2 => '75 Old Dumbarton Road',
      :city => 'Glasgow',
      :postcode => 'G3 8RG',
      :short_description => 'Great flat in Yorkhill',
      :full_description => 'This is in a great location and has top views of the university',
      :min_people => 1,
      :max_people => 10,
      :tag_list => "Dishwasher\nTV",
      :landlord_id => 1,
      :is_live => true
    }.merge(options)
    )
  end

This is great because in my tests I can run something like.

  def test_special_dom
    p = create_property(:is_live => false)
    special_dom = p.special_dom('new')
    assert_not_nil(special_dom)
    assert_equal("property_#{p.id}_new", special_dom)
  end

This means that the setup and tear down for this test is done in the test method meaning I know exactly what I am working with. If you look at line 2 you will see you I can override the default options in the test method by passing a hash of new options. This is the beauty of the merge method in test_helper.rb

2. Use the setup method in both unit and functional tests.

This is not only great for logging in users, but it also is great for running the data creation methods before you run the test and make all your test methods a little more DRY.

eg.

  def setup
    @controller = LandlordAjaxController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
    @property = create_property
    login_landlord
  end

Now all my tests in this functional test can use the @property object.

eg.

  def test_back_calendar
    xhr :post, :back_calendar, :property_id => @property.id, :month_date => Date.today.to_s(:db)
    assert_rjs :replace_html, 'months'
  end

Thats all for now. If you have any more tips for fixtureless testing please add them to the comments.

Checkbox Select Rails Plugin

November 5th, 2007 by pyrat

checkbox

I had the problem of there not being a simple form rendering solution for has_and_belongs_to_many ActiveRecord relations. I found a partial solution here: http://railshacks.blogspot.com/2007/09/helper-checkboxcollection.html

I have modified the original code slightly, and extracted it to a plugin. To install it:

  ./script/plugin install http://vorlich.ath.cx/code/excited/plugins/checkbox_select

In your model you are manipulating in the form:

  class Advertisement < ActiveRecord::Base
 
    include CheckboxSelectable
    has_and_belongs_to_many :categories
    validates_presence_of :name
    validates_uniqueness_of :name
 
  end

The include is the important bit.

In your view:

  <%= checkbox_select('advertisement', 'categories', @categories, 'name') %>

In your controller add the update_check_list method:

  def create
    @advertisement = Advertisement.new(params[:advertisement])
    @advertisement.update_check_list(params, 'Category')
 
    respond_to do |format|
      if @advertisement.save
        flash[:message] = 'Advertisement was successfully created.'
        format.html { redirect_to advertisements_url }
        format.xml  { head :created, :location => advertisement_url(@advertisement) }
      else
        assigns
        format.html { render :action => "new" }
        format.xml  { render :xml => @advertisement.errors.to_xml }
      end
    end
  end

I still need to write a collection of tests for this plugin. If you have the time please write them for me!

Upgrading Ruby on Ubuntu Dapper

November 2nd, 2007 by pyrat

dapper

Ubuntu Dapper will only install ruby as high as 1.8.4 which is not ideal sometimes. To upgrade an existing ruby installation to 1.8.6 do the following.

  sudo apt-get install build-essential
sudo apt-get install libreadline5 libreadline5-dev
wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.gz
tar -xzf ruby-1.8.6.tar.gz
cd ruby-1.8.6
./configure --prefix=/usr/local --enable-pthread --with-readline-dir=/usr/local
make
sudo make install

Even if you had rubygems you need to install it and all your gems! Again.

   wget http://rubyforge.org/frs/download.php/35283/rubygems-1.1.1.tgz
tar -xzf rubygems-1.1.1.tgz
cd rubygems-1.1.1
sudo ruby setup.rb

Now this is where you need to do a little fix. Openssl will not work out of the box and some application need it so you should just set it up now.

Note: If apt-get libssl-dev complains about a not found run: sudo apt-get update

  sudo apt-get install libopenssl-ruby
sudo apt-get install libssl-dev
 
cd ~/src/ruby-1.8.6/ext/openssl
ruby extconf.rb
make
sudo make install

And thats it!