Thumbnailing to a fixed size without stretching using attachment_fu

Posted by Craig Ambrose on May 10, 2009 at 09:54 PM

I was going to write a blog post congratulating myself on being clever for writing a little extension to the attachment_fu plugin that allowed Procs to be used as thumbnail geometry strings, thus allowing you to write custom resizing code. This was all so that I could get it to perform a resize that worked exactly as I wanted, to give me a thumbnail of fixed dimensions which scaled and cropped but never stretched the image.

Before I did so, I thought I’d better just check that attachment_fu hadn’t changed recently to make my extension not work. I take a peek at github and lo and behold, Rick and other committers have been busy beavers on attachment_fu this year, and in fact another kiwi has already added the functionality that I need.

You can find David Jones’ post on how his cropping functionality works here, although it is describing his old patch for acts_as_attachment, and with attachment_fu it’s used slightly differently, as described below.

Lets say that your users are uploading photos to your site, in a range of aspect ratios (including common landscape and portrait photos). Cropping to a square thumbnail is a problem already discussed on this blog, but what if we want to crop to fixed size that isn’t square?

Image magic geometry strings, when passed to the resize function, do not force the image to become that size if the aspect ratio doesn’t match. For example, if I specify a size of “100×75”, then an image already in a 4:3 aspect ratio will scale just fine, but a portrait image in the opposite ratio will end up 75 pixels tall as desired, but only 19 pixels wide, in order to preserve it’s aspect ratio. If instead I force the new image size, using the geometry string “100×75!”, I will get an image of the correct size, but it will be stretched and distorted.

It goes without saying that we never want to stretch. Some people like to stick with the behaviour of the first example, and simply fill the missing sections of the image with a background colour. The other option, which I prefer, is to crop the image in the dimension that doesn’t fit into the new aspect ratio. The goal is to get an image of exactly my desired dimensions, which is scaled to maintain aspect ratio, and then cropped as little as possible.

Doing this with the latest version of attachment_fu from github is as easy as specifying the geometry string “100×75c”. The “c” at the end is used to indicate that we want to use the cropping algorithm. It’s not a normal part of an image magick geometry string and it does get removed by attachment_fu when it decided what algorithm to use.

If this is not quite what you need, you might also want to check out what the “e” option does.

Comments: 0 (view/add your own) Tags: (none)

PluginInstances - A different way to use rails plugins

Posted by Craig Ambrose on March 18, 2009 at 10:19 PM

I’ve just released the PluginInstances pluging at:
http://github.com/craigambrose/plugin_instances/

This plugin allows you to have individual route sets for other plugins, including a unique instance id.

Without using this plugin you can specify a routes.rb in your plugins (as of rails 2.3), and these routes are merged into the global route set used when determining how to process the current request. This is great for allowing a plugin to introduce a set of functionality which exists only once on the site (like a login system).

The PluginInstances plugin is designed to enable individual instances of plugins to be placed in different places on the site. For example, lets say that your site is content managed, and has tabs across the top which link to various types of functionality:

In your application’s routes.rb file:

map.plugin_instances "/tabs/:id"

When a request is detected with a path like ”/tabs/23/admin”, it realises that this matches the plugin_instances route, finds the relevant instance (eg: PluginInstance.find(23)), asks that instance what plugin it represents (eg: a forum, user profile, etc), and then passes the route ”/admin” to the route set for that plugin, along with the plugin instance object. Thus, a forum plugin could be written which can be instantiated at different places in the site, and just has to scope itself using the plugin instance id.

For detailed usage instructions, see the README file displayed at the github project page .

I’m using this plugin at present to build a pluggable wiki, where each new page that you create could be just a simple page of versioned text (like a regular wiki), or it could be a calendar, a forum, etc. People using drupal will also find this sort of routing system familiar, so I’m sure there are plenty of other useful applications for it.

Keeping it Real

Posted by Craig Ambrose on March 16, 2009 at 03:03 AM

Web developers who still think it’s 2007, are only kidding themselves. Unlike the nineties, it’s not an IT bubble that’s popped, it’s an “everything” bubble that’s ending, as right around the planet, almost every industry is feeling the effects of the global slowdown.

I’m not here to preach doom and gloom, or make any predictions about the next few years. However, no predictions are needed to see that right now, our business has changed, and even the best of our entrepreneurial clients are having more trouble finding the funding they need, and having to develop on smaller budgets. If every part of the economy is being squeezed, then freelance web developers need to tighten their belts.

Over the years, my rates have risen slowly with my experience level, and considering a drop in rates makes me feel quite unfomfortable. I’m not a department store, I don’t have specials or discounts. My price has been carefully set so that I am more expensive than programmers of less experience, and less expensive than those with more.

I think, however, that some of my colleages are a bit slow in taking financial reality into account, and I’m going to drop my rates rather decisively for 2009. However, I don’t wish to encourage people to view software development as a commodity to be judged predominantly on price.

There is a huge difference in the productive output between any two given programmers on any given day. Project development costs can vary enormously depending on the developers involved. I believe I offer a fairly high-end service, with extensive Rails and agile development experience, and additional support from some of Australasia’s finest agile developers over at Cogent Consulting. I don’t do cut price deals and special offers simply because I’ll never be able to compete on price per hour with cheap outsourcing to developing nations, but I’m confident that quality software development will always win out in in the end. That doesn’t, however, mean it’s reasonable for me to continue charging the same rates when millions of people worldwide now have no jobs, and I encourage other freelance rails developers to consider this as well.

For 2009, I’m available for consulting or freelance work at a base rate of NZ$80 per hour. See that in USD, Australian Dollars or Euro. These rates apply to me only, and supplying clients with multiple developers or ongoing support contracts will need to be negotiated seperately.

I sold my cow and all I got were these url helpers

Posted by Craig Ambrose on April 20, 2008 at 11:19 PM

In rails applications, we link to other pages in our application by generating a url which maps to a particular controller (class) and action (method) using a rule which we call a route. Back in rails 1.0, we would do something like this:

<%= link_to 'Edit User', {:controller => 'users', :action => 'edit', :id => @user} %>

This is not an article on routing for dummies, I presume you already know this stuff. However, I want to recap why we do this, in case anyone has forgotten the reason for all this.

To give a point of comparison, lets assume that there were no routes in rails, and that code was directed to a particular place based on the default rules of ”:controller/:action/:id?:other_params”. A link might look like this:

<%= link_to 'Edit User', "/users/edit/#{@user.to_param}" %>

That’s actually shorter than the above. Clearly brevity isn’t the main goal here. So what are the goals of customisable routed?

Human (and SEO) Friendly URLS

If we need further parameters, we don’t want to introduce a question mark into the url. We want it to keep looking like a directory structure. If we are creating a new user inside group 5, we want a url like /groups/5/users/new, instead of /users/new?group_id=5. This goal is probably not one you have forgotten, so lets jump on to the next one.

A Single Point of Change For Url Mappings

It’s a well known bad smell in any piece of software if changing your mind about one simple concept requires you to make changes all through the code (Martin Fowler calls this “Shotgun Surgery”). If our client says, “can you change all references to ‘users’ in the urls to saying ‘people’ instead”, or “can you prefix all admin urls with /admin” then we would expect to be able to do so without too much trouble.

The beautiful thing about routing in rails is that the routes control both the generation and the parsing of urls. Back when I wrote PHP apps, I had code to parse the urls (big ugly case statements) and in some cases I had code to generate the urls, but I never bothered to create one simple system for doing both.

So, with those two goals in mind, lets travel back to the present and look at resource routes in rails 2. When we create a route with map.resource, a bunch of special helper methods are also created. This allows us to replace our initial example with

<%= link_to 'Edit User', edit_user_path(@user) %>

Lets look at the pros and cons of that.

Firstly, it’s much shorter. The hard coded string was a fair bit shorter too, so we know that brevity isn’t always the main goal, but short is generally not a bad thing.

It’s a little bit more english-like, in that it contains less symbols. However, this also means that it is less semantic. It’s easy to learn how to read urls that are specified as a hash of controller, action and params. I know how to read the resource helpers too, but there are a few different rules to learn in order to parse them mentally, and I find it takes new rails programmers a little while to figure them out.

It’s overloadable. Since it’s a method, we can declare a helper of the same name and do something completely different. This can be handy, although in practice it’s a bit dangerous since there are other ways to declare the route, so you’re not guaranteed to intercept all calls. Also, it would then give behaviour that our programmer who has now worked so hard to figure out how the restful routing helpers work something of a surprise. The principle of least surprise is worth considering.

By in large, I’m still kind of in favour of the new notation at this stage. When I first learnt it, I thought, “wow, that looks much nicer”, and that feeling is a very important argument in it’s favour. We’ve gotten a lot with this new functionality. I just want to mention the one feature we sold off without even noticing.

When generating a url we are new directly linking the view code to a single routing rule.

“WTF?”, I hear you say.

Haven’t we already established that the rails routing system decouples url generation from the controller code that it maps to, allowing us to configure the interface between them in one place (routes.rb). Why am I now saying that I’ve linked the url generation in my view to a single route and lost my ability to vary it at will?

Lets say that we wanted to map all uses of the user edit action to a totally new url. It could look like anything we wanted, previously, we had the power to do so because our request to generate a url just gave the keys and values, and our action just accepted key/value parameters, and the string we used for the url in between was totally up to the routes.

Now we’re using a method unique to this action to generate the url. By calling edit_user_path(@user), we’re not actually giving up the flexibility to decide what that method does, but if we wanted to make it map to anything other than the edit action on the users controller, nested inside no other resources, then we’d be violating all the conventions that we’d built up in order to understand the user of these helpers.

So, if we want to do something like move this action to a different resource, we find that we need to go through and use a new set of helper methods for all the links. Since we need to change each link to do this, we’re really not much better of that if we’d used hard coded strings in the links.

If you wanted to rename the users resource to ‘people’, it’s quite a tricky operation. I’ve done it many times and without foolproof refactoring tools, you need to search and replace for strings like user_ and look at each method call to see if it’s a url helper which should be renamed to edit_people_path or similar.

Recently, I’ve been experimenting with going back to expressing things as a hash. Also, in doing so I follow a set of conventions.

  • Always put spaces either side of the => operator.
  • Always use symbols for the keys
  • Always use single quotes as string delimiters for the values, if they are string literals.

This gives much more precise things to search and replace for. Lets say that I want to rename the users resource to people. I can search for all strings matching :controller => 'users'.

I’m not necessarily saying that this approach is the best, but I think that we should all consider that the goal here is simplicity. The simplest code isn’t necessary the shortest. The simplest code is the easiest to read, the easiest to learn it’s full meaning, and the easiest to change. When we got all excited about named url helper methods, I’m not sure it was at all clear how much we were giving up in return.

Using Model factories with RSpec

Posted by Craig Ambrose on February 23, 2008 at 10:12 PM

I had a lot of questions and concerns about RSpec when I first made the switch a few months ago. I’d seen a few talks on BDD in general, and watched the peepcode screencasts on rspec, and I could see that BDD tended to encourage a fairly good style of testing. I managed to find answers for most of my questions, so here’s a little list of the challenges and resolutions that I faced when I made the switch.

When I first started on rails, like a good little agile developer, I mocked out everything for my unit tests and ensured that I never actually hit the database and thus never required fixtures. I used the mocha library predominantly, but after a month or so of this I had gotten totally tangled up.

The problem was that active record objects are a bit like an iceberg where only a part of them is visible in the code, and the rest is lurking below the murky waters of your database. My tests were missing heaps of bugs caused by queries generating invalid SQL, but reliance upon properties which may or may not exist depending on the database schema, and were also far too complicated as they required lines and lines of setup code to handle all the wacky ways in which a model could interact with a database.

My solution eventually was to give in, and test things the way DHH does. Not particularly elegant, certainly not “correct” in terms of what I’d been taught regarding how to test, but it did work. The upside of these tests which often integrated a number of layers together was that I got great coverage. The downside was that I’d often get a raft of test failures if I broke a single line of code, and some things were just a bit too much effort to test and tended to motivate me not to bother. Also, the dependence on fixtures meant that as the test situations got more complex, I’d have to add more fixtures, and in doing so break other tests.

When moving to RSpec, I threw all this away, and started again on mocking everything out. RSpec helped out with a few nice extra methods, like mock_model, which can sensibly provide a mock ActiveRecord object that has the bare essentials already (like the id and to_param methods). This time I did better, but I still got a little tangled up, and I found it really hard to test methods where I was querying for record. With a mock based approach, all I could test was that I’d sent the query that I expected, not that it was actually valid SQL or that it would fetch any sensible results.

The resolution, as it turns out, lies somewhere in between.

I use mocking pretty heavily still, particularly when I’m creating or updating records. But, I also often want to deal with real data, particularly when it’s being fetched rather than created. Fixtures were a bad idea, because they created a great big data set that had to be valid for all tests. There are some plugins to provide different sets of fixtures for different scenarios, but I think that having the data used for a test in a different file is also downright confusing. Setting up for each test needs to be easy.

The solution for me was the use of a model factory, which is a pattern in some use amongst my colleagues at Cogent. I’d left the worlds of C# and C++ with a bit of a dislike of factories, being a pattern that, like dependency injection, seemed to add a great deal of complexity to a problem that is much more easily solved in a dynamic language. However, a simple model factory for testing is a different kettle of fish.

Lets say I’m testing that I can’t create a user if their email address already exists. If I was using fixtures, I’d create a user with the email address I was going to try out, but that would affect all other tests. If I created a user directly in the test then I’d need to update my test each time I changed the information needed to create a valid user. Instead, a model factory makes it look like this:


describe User, "when being created" do
it "should require email address to be unique" do
model_factory.user(:email => "craig@craigambrose.com")
user = User.create(:email => "craig@craigambrose.com")
user.should_not be_valid
user.errors.on(:email).should == "must be unique"
end
end

The user method on model_factory creates and returns a valid user. It can be called as many times as I want, and it will always return a valid user. If User contains fields that must be unique, then the data I use to populate it contains integers which increment each time. The factory methods also take arrays of options which can be used instead of these default values, which I use whenever I want to set an attribute that I care about in the test. This way, if I change what is required to create a user, all I need to change is the model factory, not every single test.

I don’t use the model factory all the time. I still make heavy use of mock_model. For each case, I try and determine which method will yield the simplest test that actually forces me to write the code that is needed, rather than just appearing to give coverage over the lines of code. Sometimes I use some mocking and some concrete objects in the same test.

I haven’t provided the code for the model_factory itself. It’s very straightforward and I’ll leave it as an exercise for the reader. Drop me a line if you have a particularly clever implementation that you’d like to share or are interested in seeing some of my code.