✓ I'm available for hire! Check out my open source work on Github or drop me an email

Douglas F Shearer

Posts Tagged with rails

There are 4 matching posts.

Using Bundler With Rails 1.2

Bundler has truly been a revolution in how dependencies for Ruby projects are managed. The Bundler site provides a guide for using it with Rails 2.3 and Rails 3, but not Rails 1.2.

This won’t matter for most people, but if you have clients on older Rails versions, it can be nice to manage dependencies in the same manner across all installations.

So here’s how you do it:

1. Create a new Rails 2.x app, and copy it’s config/boot.rb across to your 1.2 app.

2. Make the VendorBoot#load_initializer() method look like the following:

class VendorBoot < Boot
  def load_initializer
    require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
    
    # Commented out as not in Rails 1.2.x.
    # Rails::Initializer.run(:install_gem_spec_stubs)
    # Rails::GemDependency.add_frozen_gem_path
  end
end

3. Follow the Rails 2.3 Bundler guide for the rest.

I’ve only tested this setup with Webrick, Mongrel and Passenger, using Rails 1.2.6, so your mileage may vary.

 
 

Integrity Git post-receive Hook

I host a few of my repositories myself, rather than on GitHub. As a result I can’t take advantage of their marvelous post-commit hook support. Instead, when it comes to informing Integrity of new commits, I have to use a custom Git post-commit hook.

Use the following in /path/to/repo/.git/hooks/post-receive changing the login credentials, URL, and project name as necessary. Make sure the script is executable.

#!/bin/sh

# Username and password not needed if publicly accessible.
curl -d '' http://USERNAME:PASSWORD@example.com/PROJECT_NAME/builds

echo "\n\n=========="
echo "  Received push and alerted Integrity"
echo "==========\n\n"

Now whenever I push to the remote repo, Integrity is informed and grabs all the new commits to run the test suite against them. This could also work as a post-commit hook, if your Integrity CI server pulls from your local working repository.

 
 

Testing Custom Rails Validations with Shoulda

In this post, I’ll show how to write custom validations for Rails’ models, and how to test them with Shoulda, the ‘Makes tests easy on the fingers and the eyes’ testing plugin.

Rails’ ActiveRecord validations are great when you want to make sure attributes are the way you want them. But what about the use-cases where you need to write a custom one?

Creating the Validation

The validation we’ll write is called validates_positive_or_zero, which will return an error if a relevant integer attribute is negative.

Create the file RAILS_ROOT/lib/validations.rb with the following contents:

def validates_positive_or_zero(*attr_names)
  # Set the default error message.
  configuration = { :message => "Cannot be negative" }
  
  # Set a custom error message if there is one.
  configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
  
  # Check none of the object's attributes are negative.
  validates_each attr_names do |obj, atr, val| obj.errors.add(atr, configuration[:message]) if val < 0 end
end

Note: This particular validation is complementary to validates_numericality_of, you’ll get some odd failures if you don’t use it.

We need to require this file before we can use the new validation in our model:

class Badger < ActiveRecord::Base
  require 'validations'
  
  validates_numericality_of :age, :height, :weight
  validates_positive_or_zero :age, :height
  validates_positive_or_zero :weight, :message => 'no-one is that light'
end

The first validates_positive_or_zero validates two attributes at once, whereas the second validates only one attribute with a custom error message.

Testing the Validation

I feel I should give a little introduction to Shoulda, it’s one of those tools that leaves me wondering how I ever managed before. Despite the popularity of RSpec within the Ruby community, I’m not a fan, it’s just too verbose, which I find gets in the way (it doesn’t render views though, which makes functional testing a lot easier, this feature for standard Rails tests please!). Shoulda is the answer for those of us who want standard Rails tests, but with them being neater and tidier. I encourage you to check it out more fully, but for this example, I’ll stay on-subject.

For our custom validation we could test it in the regular fashion with a test_foo method, or we could write a custom method that we could use again and again without re-writing the same code. The latter is the approach we are going to take here, with the method being in the style of the other shoulda validation tests.

First up, install the Shoulda plugin:

./script/plugin install git://github.com/thoughtbot/shoulda.git

Next, create the file RAILS_ROOT/test/shoulda_macros/validations.rb with the following contents:

class Test::Unit::TestCase
  
  def self.should_only_allow_positive_or_zero_values_for(*attributes)
    configuration = { :message => "Cannot be negative" }
    configuration.update(attributes.pop) if attributes.last.is_a?(Hash)
    klass = model_class
    attributes.each do |attribute|
      attribute = attribute.to_sym
      should "only allow positive or zero values for #{attribute}" do
        assert_bad_value(klass, attribute, -1, configuration[:message])
      end
    end
  end
  
  private
  
  # Taken from the shoulda private methods
  def model_class
    self.name.gsub(/Test$/, '').constantize
  end
  
end

Now we set up our tests in RAILS_ROOT/test/units/badger_test.rb:

require 'test_helper'

class BadgerTest < Test::Unit::TestCase
  
  # This method is provided by Shoulda.
  should_only_allow_numeric_values_for :age, :height, :weight
  
  should_only_allow_positive_or_zero_values_for :age, :height 
  should_only_allow_positive_or_zero_values_for :weight, :message => 'no-one is that light'
  
end

And we’re done! I hope this was useful for you.

 
 

New Domain

The last time I made a change to my domain, it went from a numerical IP to a nice dyndns address. This time I’ve moved to a proper .com domain, with all of my own subdomains etc: www.douglasfshearer.com. The dyndns address will redirect to it, and if you type in the www, it’ll be removed, just the way I like it.

In other news, last night I discovered the work on acts_as_taggable that Labratz and I did has made it into the Rails ticketing system as a future enhancement, so hopefully it’ll make it in at some point. Thanks to msheakoski for submitting it.