My first 'acts_as' plugin 7
So, you’ve upgraded to Rails 1.2.1 and you’re working on a tool to maintain a database of all the tunes you have in your various songbooks and (eventually) your record collection. You start with:
$ ./script/generate rspec_resource MusicBook title:string author_id:integer \
abstract:text
$ ./script/generate rspec_resource Tune title:string composer_id:integer \
abc:text book_id:integer
You decide to come back to composers and authors later, so you set up your models1:
MusicBook.has_many :tunes
Tune.belongs_to :music_book
And your routes:
map.resource :music_books do |book|
book.resource :tunes
end
Problems start here
Being a cautious sort, before you start adding behaviour, you fire up a development server and go and check things with the browser. The /music_books/ stuff works fine, but once you start looking at /music_books/1/tunes things start to get weird; all of a sudden your links aren’t making sense.
The problem is, that your scaffolding is calling named routes with something like: edit_tune_url @tune, when, because of the nesting of your resources, they should really be calling edit_tune_url @tune.book, @tune. But how to fix things?
Well, you could go through all your controllers and views, replacing all the calls to named_routes with the right version. But, if you’re anything like me, you’ll get bored stiff of the repetition after you’ve fixed up the first file. And that’s before you start fixing up your controllers to do
@tune = Book.find(params[:book_id]).tunes.find(params[:id])
So, I’m going to suggest that a better bet is to install the acts_as_resource plugin I’m in the process of writing.
Making the model pull its weight
Once you’ve got acts_as_resource installed, you can just do:
Book.acts_as_resource
Tune.acts_as_resource :parent => :book
And your models will magically acquire a resource_chain which returns exactly the list of objects that your named routes need. I’m currently investigating the innards of named routes, but the plan is that you’ll never have to call resource_chain yourself, the named_route helper will do it for you and use the resulting list to build the url.
Your model class, meanwhile, gets a handy
Tune.find_resource(params)
which will find your resource, verifying that it can be reached through the chain of resources specified in your params hash, which means we can fix up the scaffolding generator to use find_resource (or, more likely, a helper method that will set appropriately named instance variables in the controller).
If I understand what simply_helpful is up to, the named_routes hack should play well with that too, which means that form_for @tune will get its url right without you having to remember to call form_for @tune.book, @tune.
Release date?
I’m not quite ready to release yet, I’m busy wrapping my head around how named routes work so I can fix ‘em up to use resource_chain. find_resource is written though.
It’s amazing how much leverage you can get, simply by adding one class attribute and a support method to your model…
Expect a release some time next week. However, if you’re desperate for a look, drop me a line and I’ll send you my local snapshot.
1 Look, vertical space is precious. Pretend this is in the usual blocky type stuff you usually find in the files you’ll find in app/models/whatever.rb
