Text

AR Model Initialization Notes

If you’re new to Rails but not to Ruby, you might be surprised to learn that Rails doesn’t use the standard Ruby initialize() method when Model.new is invoked or when a model instance is returned from a find.

If you need to add some initialization code to an ActiveRecord model, use the after_initialze callback instead:

def after_initialize
  @thing = SomethingElse.new(self)
  @foo = 'bar'
end
Text

Impressed With Comatose CMS

Often after I’m finished building the bulk of a web app, I find there are some secondary pages that need to be built. These pages are largely informational, such as an about page, a contact page, an FAQ, etc. They’re relatively static in terms of the content, but it’s always nice if we can supply our client (or ourselves) with a nice CMS-style interface to make updating them easy, and within the context of our existing application layouts. Keep it simple, keep it DRY.

The obvious thing is to cook up some sort of PagesController from scratch. This is nice because it’ll make use of your existing facilities, your authentication/authorization system, layouts, etc. It is custom, after all, and a custom fit is almost always the best fit. But it’s a fair bit of work for something that’s probably not ‘core’ to the application, and takes cycles away from other places they could be better spent.

On the other hand, you can integrate with a 3rd-party CMS or blogging package like Typo, Radiant CMS, or Mephisto. They’re all great packages and do what they do really well. The downside is you’ve got to write a fair amount of glue to hook everything together and make it look (and feel) uniform.

Another option is to use Matt McCray’s Comatose plugin, a micro CMS. It’s got all the basic functionality you want for this sort of stuff out of the box and it couldn’t be much easier to use. The real bonus is integration is almost completely seemless, which makes it (imho) the best of both worlds for this sort of project.

Installing the plugin gets you a ComatoseController and a ComatoseAdminController. You add an entry (or multiple entries, if you like) in your routes file to tell your application when to invoke the ComatoseController. You might prefer a scheme where all URLs starting with /pages are passed to Comatose, for example. Then you log into the admin controller (which also needs an entry in routes) to create the pages. All the basic management tools we need are here; pages are organized hierarchically and can be edited with great ease, using a variety of markup filters. Each page gets a number of attributes, including a title, keywords, author, etc.

Basically it’s everything we need for the bare-minimum no-frills CMS experience and nothing we don’t. Which is just the way I like it. Check it out for your next project.

UPDATE

Anyone having issues with Comatose and authentication should check out this bug report. If you’re specifying an alternate session key, you should put it in environment.rb instead of ApplicationController.

ActionController::Base.session_options[:session_key] = "_your_custom_session_id"

Comatose controllers inherit directly from ActionController::Base instead of from your application controller. So if you specify the session key in application.rb, the Comatose-driven sections of your app will be blissfully unaware of it. This means a method like logged_in? (which checks the session for your login status) will always report back as false.

Tags: ruby Rails CMS
Text

Flexible Payments With Rails & REST

Anyone who’s been playing around with the original Rails version of the Amazon Flexible Payments Service sample application has probably spent a fair amount of time swearing and complaining about how incredibly un-idiomatic and ugly it is. I know I have. It’s not that we don’t appreciate Amazon wanting to play ball with us, it’s just that it’s… well… it’s damn ugly.

But wait, a few weeks ago, a new REST-based Rails sample app was posted. This time around it’s a far more basic “hello world”-ish app, but it’s much more idiomatic and clean, a far better starting place for anyone who wants to learn how to make pay calls with FPS using Ruby and Rails. It’s also thankfully devoid of soap4r dependencies.

Just thought I’d note that, in case you’re working with FPS and haven’t stumbled upon it yet.

In related news, there’s a RubyForge project for a library called Remit, which purports to be a proper Ruby API wrapper for FPS. Tyler Hunt is the developer who’s registered the project and is working on it. With no updates since early September though, and no files released, I wonder if the project hasn’t maybe been aborted? Tyler, if you’re out there, give a shout and let us know if you need a hand.

Text

SimpleDB is RESTful & Schema-less?

So the big web service of the week announcement goes to Amazon, for their AWS SimpleDB hosted service. This should place nicely with EC2, which is an interesting service except for the fact that persistent data across sessions is problematic (every time you boot an EC2 node it’s a clean slate).

So what is SimpleDB? It’s:

  • Built in Erlang (wow, maybe Erlang is worth learning after all, right?)
  • RESTful; API returns XML
  • Schema-less
  • Non-relational

Wait, what? Schema-less? Non-relational? Yup. In case you haven’t noticed, there’s been a groundswell of interest in this area lately… Perhaps most buzz-worthy is the CouchDB project, which also uses REST for inserts and queries, storing your data in schema-less databases which Amazon confusingly refers to as “domains” (see other differences). CouchDB is pretty neat, and all the cool kids seem to like it. RDDB has similar goals. And then there’s DBSlayer, which takes the approach of wrapping a REST API around traditional relational databases (MySQL, etc).

So why the interest in moving away from traditional RDBMS, which have served us well for so many years? Simplicity. Ease of scaling. The emphasis on removing business logic from the database and keeping it in the application, where it belongs. At least, those are the arguments. I’m no expert, but I’m certainly interested. Assaf Arkin summarizes the argument much better than I can, and his article Read Consistency: Dumb Databases, Smart Services should be required reading for anyone who’s interested in the future of (dumb) databases on the web. Assaf also has a follow-up article on the merits of CouchDB, specifically. There’s a lot to think about here.

Of course, another key value prop with the Amazon service is that it’s hosted. By Amazon. They claim it’s fast and reliable (they should know a thing or two about that), and it looks to be relatively inexpensive, when you consider that the alternative is clustering your own databases for the same kind of speed and reliability. It’ll be interesting to see how this turns out and I’m anxious to play around with it.

All that said, there’s no Ruby library wrapper for SimpleDB yet. However, as Chad Fowler notes, there are already three different projects registered with RubyForge. None of them have checked in even a single file as of this writing, but you know that somebody out there is hard at work (hint hint), and I’m sure you’ll see it before too long. Alternatively, you can build one yourself.

Text

ActiveRecord: Importing YAML

Given YAML file below :

CustomWidget 
    attributes: 
        name: DoSomething
        updated_at: 2008-01-28 05:02:54
        description: Does something.
        created_at: 2008-01-28 05:02:54
    attributes_cache: {}

We can automatically instantiate the appropriate Ruby objects from this using the following code:

class CustomWidget < ActiveRecord::Base
end

YAML::add_private_type("CustomWidget") do |type, value|
  CustomWidget.new(value)
end

obj = YAML::load(File.open("template.yml"))[0]
=> #<CustomWidget name: "DoSomething", created_at: 
    "2008-01-28 05:02:54", updated_at: "2008-01-28 05:02:54", 
    description: "Does something.">
obj.save
=> true

So what we’ve done is taken YAML from one project and tried to use it to import the same data into another database (note that IDs are stripped). We define a transfer type for the YAML, providing a mapping to the class, and then we call `YAML::load` to load it up. This returns an array, in this case it contains a single `CustomWidget` object. Everything looks swell. We call `save` on the new object and it returns true.

However, if we check the `count` of `CustomWidgets` that exist in the database, we’ll find that it’s unaltered; no new record has been saved. It turns out that this is because the imported `CustomWidget` doesn’t report true when `new_record?` is called.

obj.new_record?
=> nil

In order to save itself to the database and get a new ID, the `CustomWidget` instance has to first respond correctly to inquiries as to whether or not it’s new. We’d like `new_record?` to return false. The quick-fix secret is to manually toggle the `@new_record` instance variable. If we do that, calling `save` will return true and actually save the object to the database as well this time. Big yay, right?

CustomWidget.count
=> 0
obj.instance_variable_set("@new_record", true)
obj.new_record?
=> true
obj.save
=> true
CustomWidget.count
=> 1

Yes, this is an ugly hack. Did I say ugly? I meant gross.