Using RMagick with Flickr

Posted over 7 years back at schadenfreude

In my previous article, Render Great-looking Collages with Ruby and RMagick, I showed how you can use RMagick to generate a lovely collage from a selection of random images. This tutorial will take it one step further and show you how to use RMagick with RFlickr to generate a collage from your own Flickr account or even a results from a flickr search.

4 random images found with the search term “Mazda MX-3” (my car)

Using RMagick with Flickr

Posted over 7 years back at schadenfreude

In my previous article, Render Great-looking Collages with Ruby and RMagick, I showed how you can use RMagick to generate a lovely collage from a selection of random images. This tutorial will take it one step further and show you how to use RMagick with RFlickr to generate a collage from your own Flickr account or even a results from a flickr search.

4 random images found with the search term “Mazda MX-3” (my car)

Using RMagick with Flickr

Posted over 7 years back at schadenfreude

In my previous article, Render Great-looking Collages with Ruby and RMagick, I showed how you can use RMagick to generate a lovely collage from a selection of random images. This tutorial will take it one step further and show you how to use RMagick with RFlickr to generate a collage from your own Flickr account or even a results from a flickr search.

4 random images found with the search term “Mazda MX-3” (my car)

MicroSoft’s IE-7 Released – another headache for web developers.

Posted almost 8 years back at Ajax on Rails


Current World’s software giant Microsoft finally released the new milestone IE-7.
Once again web programmers have to reload their guns to cross a new barrirer of all new standards of MicroSoft another thing IE-7.
Its a feel of proud for Microsoft to not to follow the web-standards of W3C and to give themselves a fresh new region of narrow mentality people and a feel of headache for web developers to again customizing their previous running web-sites which already been specially customized to go ok with a mess IE-6 and here is a repeated story again coz the most amazing thing is that IE-7 is even not following the styles of IE-6

Go FireFox !! Go Flock !!

BillMonk - Ruby on Rails Podcast

Posted almost 8 years back at Ruby on Rails Podcast

The founders of BillMonk talk about building a community site with Rails, email as an API, and dynamically generated graphics.

Blogging for Britain

Posted almost 8 years back at Luke Redpath - Home

An interesting article dropped into my newsreader this morning. The National Trust are organising what they hope to be “Britain’s biggest blog” by encouraging people to blog about a normal day living in Britain. The blog entries will then be archived and stored in the British Library amongst other places.

As a relatively new blogger (this blog is my fourth attempt at getting a blog going and has been up and running since May this year), I’ve tried to avoid blogging about the mundane day-to-day aspects of life but I have to admit that this sounds like an intriguing idea that I’d really like to have a go at.

If you live in the UK and you’d like to take part yourself, entries can be uploaded between 17 – 31 October on the History Matters website. It doesn’t have to be more than 650 words long. I’ll be picking a day in the coming fortnight to give it a go (hopefully an interesting day!) and I’ll post my entry up on here too.

Go on, blog for Britain!

Aslak Hellesoy - Ruby on Rails Podcast

Posted almost 8 years back at Ruby on Rails Podcast

A member of the rSpec team talks about Behavior Driven Development. From the offices of Bekk in Oslo, Norway.

Make ruby-mysql create less garbage

Posted almost 8 years back at RailsExpress.blog

During the preparation of my RailsConf2006 talk I did some comparative benchmarks with Mysql and Postgresql. To my astonishment, I observed that Rails with Mysql created many more objects. After digging into the C part of ruby bindings of Mysql, I discovered that the Mysql bindings create a copy of the columns name string for each record retrieved from the database. This obviously leads to quadratic memory use and calls for correction.

I’ve written a small patch for the ruby-mysql bindings and submitted it to the author, but never got a response, although a tried several times.

You can get the patch here.

The patch actually goes a little farther than just correcting the n*m problem. I have added a Mysql::Result.all_hashes method, so that the entire array of hashes creation runs in C.

For pages that retrieve small datasets, you will probably see only a small increase. I measured around 5% increase for pages that load 25 objects. Which is neat. But the patch really shines when you retrieve large data sets. For example, for loading 1000 objects, I got this perf data:

<style type="text/css">

</style>
page c1 totalc2 total c1 r/sc2 r/s c1 ms/rc2 ms/r c1/c2
/alphabetic 6.861265.20610 14.619.2 68.6152.06 1.32
GC statistics c1 totalc2 total c1 #gcc2 #gc c1 gc%c2 #gc% c1/c2
2.142501.18728 24.012.0 31.2322.81 2.00

30% faster!

But more important, a lot less gargabe gets created (in the example GC runs twice as often with the unpatched bindings).

You can take advantage of this by creating your own garbage ;-)

Oracle support for sql_session_store

Posted almost 8 years back at RailsExpress.blog

Due to a contribution from Tiago Macedo, sql_session_store has gained Oracle support.

If you’re on Oracle and want improved session handling performance, you should give it a try.

If you find any problems, please submit bug reports/patches here.

And if you now how to and have time to implement support for other database adapters, please send an email or better, create a ticket and attach the patch.

Chris Pine - Ruby on Rails Podcast

Posted almost 8 years back at Ruby on Rails Podcast

The author of the Learn to Program website and book talks about learning and teaching Ruby.
Also check out the forum donated by core member Rick Olson and coding mastermind Josh Goebel.

Introduction to ActiveSpec

Posted almost 8 years back at Luke Redpath - Home

As I mentioned in a previous article, during my downtime last week I have been working on a Ruby library called ActiveSpec. Other than a quiet announcement on the Rails mailing list (and an accidental one on the Rails core list) little has been said about it, until now.

Specifications

Not to be confused with the kind of specifications we talk about when using the RSpec BDD framework, the Specification design and analysis pattern can form a part of your core domain model. The easiest way of describing a specification is a collection of rules. Objects can be evaluated against the rules of a specification and should all of those rules be met, the specification is satisfied. The Specification pattern can be used to decouple those rules from your core domain objects. This can be especially useful when the evaluation of a series of business rules depends on several domain objects at one time.

The Specification pattern borrows from logic-programming and the concept of predicates – a specification object is a an object that essentially evaluates to a boolean. Different specification objects can then be combined to create more complex specifications (a composite). Domain Driven Design, by Eric Evans, concisely summarizes this as follows:

“Create explicit predicate-like VALUE OBJECTS for specialised purposes. A SPECIFICATION IS A PREDICATE that determines if an object does or does not satisfy some criteria.”

There are three main uses of the Specification pattern:

  1. Validation
  2. Selection
  3. Creation (build-to-order)

The simplest of these is validation and that is what the initial release of ActiveSpec focuses on.

What is ActiveSpec?

ActiveSpec is a Ruby implementation of the Specification pattern. At the lowest level, it provides a series of generic Specifications that will be familiar to anybody who has used Rails validation macros. It also provides a way of creating composite specifications in a more declarative manager and on top of that, a simple DSL that can be used for easily defining specifications. Finally, it makes it easy to declaratively link your own classes to specifications depending on context.

Where would you use it?

As I mentioned before, one of the main uses of the Specification is for validation. More specifically, it can be used for evaluating objects, or a combination of objects against a series of complex business rules. Validation was the initial motivation for creating ActiveSpec and it was designed as an accompaniment – not a replacement – for ActiveRecord’s built-in validation macros. Furthermore, ActiveSpec is not limited to use with ActiveRecord or indeed, Rails. It can be used with any Ruby object.

ActiveRecord’s validation macros make it easy to declaratively add data validation to your model objects. A lot of the time these are enough and for basic validation (such as size constraints) they work well. On a recent project, with a particularly complex domain model, there was the need to validate objects in different ways, depending on its state and relationship with other objects. We found there was a lot of pushback as we tried to bend ActiveRecord validations to apply the complex business rules needed. We managed it, but the resulting code wasn’t pretty and certainly not the elegant, clear code you would come to expect from a Ruby or Rails application. In retrospect, the Specification pattern would have been an ideal solution.

Getting started with ActiveSpec

Before we can do anything, we need to install ActiveSpec. This can be done easily using RubyGems.

$ gem install activespec

We’ll start by taking a look at the ActiveSpec::Specifications module. This module contains low-level, generic Specifications, that match a lot of the functionality provided by ActiveRecord’s validation macros. These include:

  • CollectionSpecification (validates_inclusion_of and validates_exclusion_of)
  • ConfirmationSpecification (validates_confirmation_of)
  • PresenceSpecification (validates_presence_of)
  • SizeSpecification (validates_size_of)

All specifications in ActiveSpec conform to the same, simple one-method interface, satisfied_by? In addition, all of the above Specifications can be used against multiple attributes of an object, in a similar way to the ActiveRecord validations macros. Here’s SizeSpecification in action:

user = User.new(:username => 'luke')
spec = SizeSpecification.new(6, :username)
spec.satisfied_by? user
#=> false

On the face of it, this offers nothing different to using validates_size_of :user, :is => 6 On their own, these low-level Specifications offer little, except for an alternative implementation of the built-in ActiveRecord validations. Its when you start combining them with other low-level specifications, as well as your own custom specification objects, to create more complex specifications that their power becomes more obvious.

Composite specifications

To aid in the creation of composite specifications (a collection of specifications that can be treated as an individual specification due to a matching interface), ActiveSpec provides a CompositeSpecification class:

spec = CompositeSpecification.new
spec.add_specification(SizeSpecification.new(6, :username))
spec.add_specification(CollectionSpecification.new(18..30, :age))
spec.add_specification(ConfirmationSpecification.new(:password))
spec.satisfied_by?(User.new)
#=> false

Of course, because a CompositeSpecification and a single Specification share the same interface, there is no reason why you can’t add composite specifications to other composite specifications.

Finally, ActiveSpec provides two low-level convenience classes. The first is a decorator called NotSpecification. You can use this to reverse the result of a specification (i.e. if a specification returns true, then it will return false when wrapped in a NotSpecification decorator). One potential application of this is in the implementation of both validates_exclusion_of using the CollectionSpecification:

spec = CollectionSpecification.new(1..10, :age)
# or validates_inclusion_of :age, :in => 1..10

spec_two = NotSpecification.new(CollectionSpecification.new(1..10, :age))
# or validates_exclusion_of :age, :in => 1..10

The second convenience is a simple adapter that can be used to wrap around Proc objects to make them conform to the specification interface. This makes it possible to use Procs as ad-hoc specifications:

spec = ProcSpecification.new(proc{ |object|
  # do something with object
  # and return true or false
})
spec.satisfied_by? some_object

Taking things further with ActiveSpec::Base

So far we’ve demonstrated some of the built-in ActiveSpec generic specifications can be used in place of ActiveRecord validations and how they can be combined to create more complicated specifications. Whilst this forms the core of ActiveSpec’s functionality, using these low-level specifications directly isn’t very elegant. ActiveSpec::Base allows you to construct composite specifications in a much more declarative manner that will feel a lot more comfortable for those used to ActiveRecord validations. All you need to do is inherit from ActiveSpec::Base.

class UserSpecification < ActiveSpec::Base
  requires_presence_of :username, :password
  requires_size 6, :password
  requires_confirmation_of :password
  requires_inclusion_in 18..30, :age
end

UserSpecification.satisfied_by?(some_user)

For every built-in low-level specification, there is an equivalent must_satisfy You can also pass in a block to must_satisfy and it will automatically be converted into a ProcSpecification.

bc(ruby). class AdvancedUserSpecification < ActiveSpec::Base
must_satisfy :valid_user_specification
must_satisfy do |user|
# do something with user
end
end

Finally, the ActiveSpec::Context module defines a specification method will be made available in the global namespace. Using it couldn’t be simpler:

specification :valid_user do
  requires_presence_of :username, :password
  requires_confirmation_of :password
  must_satisfy :another_specification
end

ValidUserSpecification.satisfied_by?(some_user)

As you can see from the above example, all of the macros available in ActiveSpec::Base are available to the DSL. The DSL will automatically create a specification class that inherits from ActiveSpec::Base which can then be used in the same way as your other specifications.

Using the Satisfies mixin for easy integration

The final piece of the ActiveSpec puzzle is the ActiveSpec::Satisfies mixin which makes it possible to attach specifications directly to a class. Whilst this increases coupling, there are times when you always want a class to pass one or more specifications and manually passing objects into specification objects can get quite tedious. The ActiveSpec::Satisfies mixin adds two new methods to your class – a class method called satisfies_specs? If the use isn’t obvious, allow me to demonstrate:

class User
  must_satisfy :valid_user_specification

  # optional :if argument takes a symbol or a block
  # and can be used for conditional evaluation of
  # specifications
  must_satisfy :activated_user_specification, :if => :activated?
end

user = User.new
user.satisfies_specs?
# evaluates ValidUserSpecification
user.activated = true
user.satisfies_specs?
# evaluates both specifications

If you want to use this functionality in your Rails models, add this to your environment.rb file:

require 'active_spec'
ActiveRecord::Base.send(:include, ActiveSpec::Satisfies)

There are plans to make ActiveRecord integration easier in the future with the use of a Rails plugin.

Give it a try!

ActiveSpec is still in its early stages – its only at version 0.1. The next release will focus on improvements to the existing code and tackling the second use of specifications for selection. Work on this is still in its early stages, but here is a small teaser:

# pure ruby selection
User.find_by_specification(SomeAdvancedUserSpecification)

# specifications for SQL queries?
User.find(:all, :conditions => SomeAdvancedUserSpecification.to_sql)

If you have some cool ideas for ActiveSpec, or feedback on any of the above, please let me know.

Further information

RailsConf Europe 2006: In Review

Posted almost 8 years back at Luke Redpath - Home

RailsConf Europe was really great for the most part. There were some awesome keynote talks (sorry, “plenary”) with particular highlights being Dave Thomas’ excellent closing talk (which fully deserved the standing-ovation it deserved. Kathy Sierra also gave an awesome talk on creating passionate users. Both were the most confident and professional speakers of the two days but there were many other great talks as well, especially on the Thursday.

A personal highlight was seeing how popular Dan’s UJS talk was. I’ve already spoke about the talk but I must restate how cool it was to see the main hall fill out during Friday lunchtime after Dan was asked to repeat his talk due to so many people being disappointed on the Thursday morning. Speaking of UJS, we hope to have 0.4 out soon but a combination of my lack of net access last week and the both of us being really busy means that it might be a few more weeks yet. We have fixed a good few bugs however so we might push a point release in the meantime; I haven’t decided yet.

Gavin Bell and Tom Armitage (who I’d seen give an excellent talk at LRUG) gave an interesting talk on polymorphism as a pattern in social software. I felt that perhaps their overall point got lost a little but it was interesting nonetheless. It was cool to see testing with Javascript getting a good airing by Thomas Fuchs (see my live notes on his talk) and Marcel Molina Jr. showed some useful tips and tricks for sharing and reusing RJS code. An unexpected highlight of Marcel’s talk came towards the end when DHH and Piers Cawley got into a small disagreement over the separation of concerns between models and views – for the record I think DHH was spot on and I was somewhat confused at Piers’ ranting. It was entertaining though.

Photo of notes

Apart from DHH’s opening address, which I’ll come to shortly, the other talk that sticks in mind was Jim Weirich’s talk. He gave a great overview on “playing safe with others” and how to write good Ruby code without unintended side-effects. I’m too lazy to write up my notes, but you can click on the image above for a larger view of my Moleskine scribblings – sorry about the dodgy handwriting!

David Heinemeier Hansson gave a great talk to kick the conference off, which was mostly about code (with all of his slides in Textmate as he didn’t have Keynote on his laptop…cool!) and I have to say that I’m finally convinced about ActiveResource and REST. Simply Helpful looked really neat as well. The one part of David’s talk that I didn’t get to see was the part he had to postpone until the core team chat later in the day (I was already on the way home for an early night by that point). I didn’t see it, but its hard not to know all about it. I’m sure you’ve all seen the photo. So what was my reaction? To be honest, disappointment.

I know David likes to make controversial statements in this way (we all remember “Fuck You”). He’s one strongly opinionated guy and in many ways it can be a positive quality (one that comes across heavily in Rails). And in some ways I agree with him – just because you download a piece of open source software it doesn’t mean you are entitled to anything. You aren’t entitled to support, developers aren’t obliged to listen to your feature requests and ideas and they certainly don’t have to listen to (or deserve) unconstructive criticism and bitching. However well you thought the recent Rails security hole was handled there was no call for some of the petty bitching, moaning and whining that some people felt the need to do. Constructive criticism is fine and should be encouraged but whining helps nobody.

What I don’t agree with is David’s black and white attitude towards people. I don’t like the notion of “if you haven’t contributed back to the community then I don’t care what you have to say”. Just because somebody might be new to the community or hasn’t had the time to contribute much to the community be it in the form of patches, plugins, or help on the mailing list it shouldn’t meant that they should just be ignored by default. David may well have no legal responsibility towards anybody who downloads and uses Rails – a point he has been quite clear about. But in my most humblest of opinions, when you put out a piece of open source software like Rails, promote its use and see it grow into what it has become today, with many developers and companies livelihoods depending on Rails you carry a certain degree of moral responsibility to those developers. Giving a big “fuck you” to people just because they haven’t yet made some kind of contribution back to the community is short-sighted and somewhat immature and I was disappointed not so much by the point David had to make, but the way in which he made it and had I been around for the core panel talk I’m sure I would have left with a somewhat bitter taste in the mouth.

After that last sentence it would be somewhat ironic for me to end my RailsConf thoughts on that note so let me get back to being positive. The conference was well organised (except for those shitty passes) and most of the talks were interesting. Above all else, I had a great two days and got to meet some great people. Damien, Max, Robby, David, Jarkko, James, all the guys at Aegis Media and everybody else I met over those two crazy days. It was great to meet you guys and share some beers! Here’s to RailsConf Europe 2007 – see you in Berlin!

Give me my Internet back!

Posted almost 8 years back at Luke Redpath - Home

Just in case you’ve been wondering where I’ve been…allow me to explain. Warning: ranting ahead!

Last week mostly sucked, no thanks to the two companies above. Last month Sky announced that they were launching a new ADSL service called Sky Broadband. They were offering up to 16Mb with no caps for only £10 per month for Sky TV subscribers. My previous ISP, Zen Internet were good with decent support, but they were not cheap: £25 per month for up to 8Mb (I never got more than 3Mb) and a 20GB cap is not what I call good value for money. How could I not jump at the offer?

It turns out that it was the worst decision I’ve made in a while. Through a combination of Sky’s complete and utter incompetence and lack of communication and what I can only assume is laziness and more incompetence on BT’s part, I have been without broadband net access at home since September 15th, which is when my Zen connection was cancelled. To make matters worse, we just moved offices here at Agile Evolved and we didn’t get broadband installed until September 21st – nearly a week without any net access! My Sky connection should have been activated on the 11th but it wasn’t. With RailsConf coming up I decided to wait until the following Monday to chase things up, and so began a week of constantly calling Sky (with up to half hour hold times) trying to find out what on earth was going on, only to be told that “there was a delay at BT’s end”. You see, because Sky is a LLU (local loop unbundled) service, BT, who run the phone exchange have to physically connect you to Sky’s hardware. It never happened. At one point I was told there would be up to a 30 day delay. That’s just not acceptable.

Sky must have known that demand would be massive so I don’t buy any excuses of “underestimating the demand”. Nor do I buy the complete passing of the buck to BT – Sky have to take responsibility too as they are the ones selling the services whilst BT struggle to cope.

Things can’t get any worse you might assume, but after cancelling my order yesterday, I rang up to confirm with Sky that it had been cancelled. I was told that it has and that the cancellation had been sent through to BT. Unfortunately the order has left what is known as a “marker” on my line which prevents me from ordering broadband from anybody else until it is removed. I rang up BT’s wholesale division to have it removed and even though the lady was very helpful she told me that it my line was showing up as having an “incompatible product” and that it could take up to two weeks to have the marker removed. She promised to put it through as urgent and said that it could be done by next Monday, even tomorrow but the possibility remains that I will be without net access at home for another two weeks.

The bottom line…if you are in the UK and were thinking about getting Sky Broadband – don’t bother. At least, not for now. Wait until things are settled down a bit – I might be willing to give them another chance in 3 to 6 months but I seriously advice people to give them a miss for now unless you have some kind of backup, like a cable broadband connection that you can leave active until your Sky Broadband connection is up and running. If only I could get cable where I live, as I used Telewest cable when I lived in Wolverhampton and I never had a problem.

And breathe…

If there was one good thing that came out of my downtime last week it was that I was able to spend some time developing my Ruby Specifications library, ActiveSpec. More on that soon…

New plugin: query_builder

Posted almost 8 years back at RailsExpress.blog

I’ve added another plugin for you to check out: query_builder.

This plugin enables you to define finder methods that bypass the overhead of construct_finder_sql.

Inside an ActiveRecord model definition,
  define_finder query_name, query_type, options_hash
will create a SQL query method called query_name from a given options_hash. query_type can be :first or :all. The plugin supports all options except :include, but ignores with_scope options. Example:
class Recipe
  define_finder :find_all_of_user, :all,
     :conditions => 'user = :user AND priv < :priv'
  end
This defines a query method which can be called like so:
Recipe.find_all_of_user :user => 'martin', :priv => 1
This call is equivalent to
Recipe.find :all, :conditions =&gt;
            [ 'user = :user AND priv < :priv',
              {:user => 'martin', :priv => 1} ]
If options[:positional] is not nil or false, the created query method will use positional paramaters instead of a hash. In this case, arguments are created in the order of appearance on the parameters passed to define_finder. Therefore
define_finder :find_all_of_user, :all,
      :conditions => 'user = :user AND priv < :priv',
      :positional => true
will create a query method with parameters user and priv, which can be called like so:
Recipes.find_all_of_user('martin', 1)

I converted one of my pages to use this style and it gained 10% more performance.

If you like this plugin, drop me a line. If you find a bug, please submit a bug report to Trac

Enjoy.

Debain Sarge Spam Killer - Postfix, Spam Assassin, Razor, DCC and Procmail

Posted almost 8 years back at Eric Goodwin

About three weeks after putting my email address on the main page of my blog I started to get spam, and a lot of it. That’s when I decided to install Spamassassin. To help Spamassassin to detect spam I also installed DCC and Razor, two anti-spam filters. Here’s what I did and how I did it.

This tutorial assumes that you have postfix up and running already.

First lets walk through the steps that postfix goes through when you receive an incoming email.

When receiving an email postfix looks for .forward in your home directory and executes any commands that you have in this file. If postfix doesn’t find a .forward file then it will execute /etc/procmailrc with no options and afterwards execure ~/.procmailrc if it can find that file.

Ok, let’s get started.

Spamassassin

server:/# apt-get install spamassassin
server:/# adduser --system --home /var/lib/spam --shell /bin/false --disabled-password --disabled-login spamd
server:/# pico /etc/default/spamassassin
Change ENABLED=0 to ENABLED=1
server:/# pico /etc/postfix/master.cf
Look for a line like this:
smtp      inet  n       -       -       -       -       smtpd 
and on the following line add:
-o content_filter=spamassassin
And at the end of the file add this line
spamassassin unix - n n - - pipe flags=Rq user=spamd argv=/usr/local/bin/sa-filter.sh -f ${sender} ${recipient}
Now let’s create the file we just refered to in the previous line of code.
server:/# pico /usr/local/bin/sa-filter.sh
And let’s add this into it
#!/bin/bash
/usr/bin/spamc | /usr/sbin/sendmail -i "$@" 
exit $?
Now that that’s done, make sure that spamd is the owner and then restart everything.
server:/# chown spamd:spamd /usr/local/bin/sa-filter.sh
server:/# chmod 755 /usr/local/bin/sa-filter.sh
server:/# /etc/init.d/spamassassin restart
server:/# /etc/init.d/postfixreload

Razor & DCC

server:/# cd ~/
server:/# apt-get install razor
server:/# wget http://www.dcc-servers.net/dcc/source/dcc-dccproc.tar.Z 
server:/# tar xfvz dcc-dccproc.tar.Z 
server:/# cd dcc-dccproc-* 
server:/# ./configure
server:/# make
server:/# make install 
server:/# rm dcc-dccproc.tar.Z
server:/# rm -Rf dcc-dccproc-*
First lets make sure that DCC is working.
server:/# cdcc info
You should get a big long list of servers. Next let’s get Razor all set up.
server:/# cd /etc/mail/spamassassin 
server:/# mkdir .razor 
server:/# razor-admin -home=/etc/mail/spamassassin/.razor -register 
server:/# razor-admin -home=/etc/mail/spamassassin/.razor -create 
server:/# razor-admin -home=/etc/mail/spamassassin/.razor -discover
server:/# pico /etc/mail/spamassassin/.razor/razor-agent.conf
We have to add one line to this file
razorhome = /etc/mail/spamassassin/.razor/
It will most likly be the only line in the file. Now let’s open up the spamassassin local config file
server:/# pico /etc/mail/spamassassin/local.cf
We want to add two lines at the end of the file
/etc/mail/spamassassin/.razor/razor-agent.conf
use_dcc 1 dcc_path /usr/local/bin/dccproc dcc_add_header 1
One last thing we need to do is add DCC to your spamassassin init file.
server:/# pico /etc/mail/spamassassin/init.pre
Add this to the end of the file
loadplugin Mail::SpamAssassin::Plugin::DCC
Now restart Spamassassin and reload Postfix.
server:/# /etc/init.d/spamassassin restart
server:/# /etc/init.d/postfix reload

Procmail

Ok, we have to decide what to do once an email gets labeled as spam. First off let’s make sure that all email goes through procmail.
server:/# pico ~/.forward
Now lets add a line. Make sure to keep the quotes.
"|exec /usr/bin/procmail || exit 75"
Before we create our procmail instructions we need to do a couple things. First we want to create a new folder in our mail dir called “Spam” which we’ll forward all our spam to. Next we have to take note to where our shell is located.
server:/# touch ~/mail/Spam
server:/# which sh
/bin/sh 
Now let’s tell Procmail what to do.
server:/# pico ~/.procmailrc
Make sure bash is set to the value you got before. Also change the MAILDIR to wherever your mail directory is. I’ve asumed it’s in ~/home/mail.
#Preliminaries
SHELL=bin/sh
MAILDIR=${HOME}/mail
DEFAULT=$MAILDIR/ 
:0:
* ^X-Spam-Flag: YES
$MAILDIR/Spam
Now if anything is flaged as spam it will automatically be moved into the spam folder. Let’s restart spamassassin and postfix one last time, for good luck.
server:/# /etc/init.d/spamassassin start
server:/# /etc/init.d/postfix restart

Now sit back, relax and reminisce about the days when you used to get spam.

Resources

http://blog.psuter.ch/index.php?/archives/29-installing-spamassassin-on-debian-with-postfix.html
http://aaron.birenboim.com/unix/postfix+spamassassin.htm
http://linux.duke.edu/~mstenner/docs/sa-docs/advanced.html
http://www.cs.rutgers.edu/~watrous/procmail-spam.html