Archive for the 'Ruby (on Rails)' Category

Deploying to Heroku from TeamCity

Previously I discussed our TeamCity configuration using RVM and mentioned that we often use git to deploy projects. Today I’ll share an example of how a TeamCity build agent can trigger deployments of a application hosted on Heroku and some of the challenges I found.
Continue reading ‘Deploying to Heroku from TeamCity’

Using RVM on TeamCity build agents

We have been using TeamCity to manage the continuous integration, testing, and deployment of many of our recent projects. We have also been using RVM on all of our recent Rails projects to allow us to install multiple ruby versions and create isolated gemsets for each project. RVM proved to be particularly useful on our TeamCity build agents where it allows a single agent to build many projects without the fear that we will see gem or ruby version conflicts between projects or introduce dependencies on gems installed on the build server but not enumerated in the project. Here’s the configuration I have used to get our build agents to use each project’s RVM settings.
Continue reading ‘Using RVM on TeamCity build agents’

How to install rails on CentOS 5.4 x64

1. Download ruby source

wget http://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7.tar.gz
tar -zxvf ruby-1.8.7.tar.gz

2. Install dependencies

sudo yum install gcc
sudo yum install gcc-c++
sudo yum install zlib-devel
sudo yum install openssl-devel
sudo yum install readline-devel
sudo yum install sqlite3-devel

3. Build ruby from source

cd ruby-1.8.7
./configure --with-openssl-dir=/usr/lib64/openssl
make
sudo make install

4. Download rubygems source

wget http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz
tar -zxvf rubygems-1.3.6.tgz
cd rubygems-1.3.6
sudo ruby setup.rb

5. Install gems

sudo gem install rake
sudo gem install rails
sudo gem install sqlite3-ruby (optional)

Test-Driven JavaScript with ScrewUnit and BlueRidge

Jonah and I are taking our presentation about Javascript Testing on the road next Tuesday at 6:30 in Palo Alto, at the SDForum

The teaser for it… Recent evolutions in JavaScript testing frameworks now allow creating test suites, test-driving development, and running tests on a continuous integration server. This allows us to support more complex JavaScript, have confidence in the implementation, and push more of the logic from the server into the browser, reducing the load on the server…

Hope to see you there.

Erector views – undefined method `default_url_options’

I’m posting this because it took me too long to figure this out. Hope it saves someone else some trouble. If you want to use named route helpers to generate urls in your erector widgets you need to include ActionController::UrlWriter in your class, like so:


class Views::Layouts::BasicPage < Erector::Widgets::Page
include ActionController::UrlWriter
...
end

Automatically deploying to Engine Yard Cloud

I’m working on a application which is deployed to Engine Yard’s Cloud infrastructure and I wanted to automatically redeploy the application whenever our tests passed on our continuous integration server.

Engine Yard will eventually allow us to push a branch to our cloud environment from git (ie “git push engineyard master”) but until that is available the best option seems to be to trigger a github post receive hook directly.

To that end I rewrote an existing script to trigger post receive hooks as a rake task; http://gist.github.com/271433
Continue reading ‘Automatically deploying to Engine Yard Cloud’

assert_changes and assert_no_changes in Ruby

Update: This code and documentation is now available on github: http://github.com/ndp/assert_changes/tree/master

The Problem

On our work on gobalto.com, we spend time to have good fixture data for our tests– data that can represent all the important application states that our tests require. As a result, our tests are very dependent on the data. It’s important that someone doesn’t inadvertantly change it in subtle ways. This has led us to write not only asserts at the end of tests, but pre-conditions as well. For example,

    ...
    inotech = companies(:inotech)
    assert inotech.services.public.include?(categories(:a))
    assert inotech.services.public.include?(categories(:b))
    assert inotech.services.public.include?(categories(:c))
 
    post :edit_services_dialog, :id=&gt;inotech.id,
                                          :service_category_id=&gt;categories(:a).id
    inotech.reload
 
    assert inotech.services.public.include?(categories(:a))
    assert !inotech.services.public.include?(categories(:b))
    assert !inotech.services.public.include?(categories(:c))

Although the pre-conditions were introduced to guard against accidentally changing fixture data (or just to figure out what’s going on), we don’t necessarily delete them. They provide stronger tests. And in some ways, leaving in pre-conditions make the code more readable by providing documentation of your assumptions to the readers. The code above would be hard to follow without the clarifying pre-conditions. What do we expect to change and what stays the same?

Unfortunately all these asserts make the tests twice as long. And there’s a subtle readability problem: there’s no relationship between the corresponding pre- and post-conditions. In the example above, you have to scan carefully to see that the three assertions are repeated, but negated (b and c only). The reader must mentally put pieces together. And it’s not DRY. Using local variables doesn’t help much.

The Solution

I was inspired by a nice little test helper called assert_difference. It takes a string to evaluate and a block to execute. It’s useful for checking on state changes– especially database changes– during a test:

assert_difference('Company.count', -1) do
    Company.delete_one
end

(Without this method, we rely on a count of all database records, or merely look for specific ones. The former approach leads to brittle tests, and the latter to incomplete assertions.)

A limitation of assert_difference is that it only deals with integers. What if it were generalized? Here goes:

    i = true
    assert_changes 'i' =&gt; false do   # read as: i changes to false
      i = false
    end

Continue reading ‘assert_changes and assert_no_changes in Ruby’

Convenient CSS and Javascript in Ruby on Rails

I get tired of hunting through a hierarchy of folders and files, from the views to the public folder, to locate a certain CSS or Javascript file. It’d be convenient to have them right with the markup, but embedding these definitions within your HTML markup is a bad idea for several reasons. For our current project, I proposed we put everything in the view directory so they are easy to find:

app/
  views/
    home/
      index.html.rb
      index.css
      index.js

The convention is clear: to add page-specific CSS code, just create a new file with the same name as the view, in the same folder. Easy to add, edit and remove. The alternative (using the public folder), usually leads to a parallel hierarchy and the inconvenience of that.

I also thought, that this being Rails and all, the files should be included automatically. It turned out to be pretty easy. Continue reading ‘Convenient CSS and Javascript in Ruby on Rails’

Using paginating_find with has_finder

I’ve been enjoying using has_finder by Nick at Pivotal Labs and recently added pagination to the application I am providing volunteer time to for the San Francisco Bike Kitchen.

I like the semantics of paginating_find over will_paginate but am not married to that choice if anyone wants to try to convince me otherwise.

In any case, I wanted to paginate the finders created by has_finder. I wrote a simple ActiveRecord mixin that provides a class method ‘acts_as_paginated and is used in your model like:

class Visit < ActiveRecord::Base
  belongs_to :person
 
  acts_as_paginated :size=> 10
 
  has_finder :for_person, lambda { |person| {
    :conditions => { :person_id => person},
    :order => 'datetime DESC'
  } }
 
  has_finder :in_date_range, lambda { |from,to| {
    :conditions => [ "visits.datetime >= ? and visits.datetime <= ?", from, to ]
  } }
end

Client code looks like:

from, to = Date.new(2008,2,1), Date.new(2008,2,3)
visits = Visit.for_person(@person).in_date_range(from, to).paginate(:page => 3)

The mixin looks like:

# Provides Model.paginate(options={}) to allow
# the paginating_find plugin to be used with the has_finder plugin.
#
# Usage:
#   acts_as_paginated
#   acts_as_paginated :page => 2, size => 10
#
# Install:
#   Save this file as lib/acts_as_paginated.rb and require 'acts_as_paginated'
#   in environment.rb.
#
module HasFinder
module PaginatingFind #:nodoc:
 
def self.included(mod)
  mod.extend(ClassMethods)
end
 
module ClassMethods
  def acts_as_paginated(options={ :page => 1, :size => 20})
    cattr_accessor :paginate_defaults
    self.paginate_defaults = options
 
    self.class_eval do
      extend HasFinder::PaginatingFind::SingletonMethods
    end
  end
end
 
module SingletonMethods
  def paginate(args={})
  options = self.paginate_defaults.clone
    options[:page] = args[:page].to_i if args[:page]
      options[:size] = args[:size].to_i if args[:size]
        find(:all, :page => { :size => options[:size], :current => options[:page], :first => 1 })
      end
    end
  end
end
 
ActiveRecord::Base.send(:include, HasFinder::PaginatingFind)

It also works to paginate associations:

@person.visits.paginate(:size => 4)

markaby_scaffold Rails Plugin

We’ve been enjoying using Markaby on our recent rails projects. When bootstrapping with scaffolding there’s a common recipe of turning ERB views into Markaby and then refactoring views with Markaby helper functions.

One project wrote a rake task that converts ERB views to Markaby. Then Ingar created a plugin that re-implements the base Rails scaffolding to create Markaby views that output the same HTML as the base Rails scaffolding. I took his work one standard refactor further to introduce a MarkabyHelper with helper functions for the layout of form inputs and model views.

Usage

./script/plugin install http://svn.carbonfive.com/public/carbonfive/rails/plugins/markaby_scaffold/trunk/

Use it as you would regular Rails scaffolding:

./script/generate markaby_scaffold Post title:string body:text published:boolean

Prerequisites

markaby_scaffold requires that you install Markaby as a Rails plugin.

Gravy

Unfortunately, Markaby does not appear to be getting the love that it deserves. There is an issue using Markaby with Rails 2.0.2 for which Randy has submitted a patch. This plugin includes a monkey patch for Markaby and Rails 2.0.2 that provides this fix so you don’t have to apply it yourself.

Additionally, the generated MarkabyHelper includes support for using Markaby in your helpers, provides a quick start for refactoring the scaffolding layouts and includes test cases to get you started testing your Markaby helpers.