Hey all,
With the recent release of Mac OS X 10.5 (aka Leopard) - There is a lot of buzz about all the new features - but in the last day or so - I've noticed something that isn't getting a lot of press: Some things have been removed.
So far - it seems only the mac/unix geek crowd may notice the things that are gone. Being firmly in that category - I've noticed.
The big one I noticed the hard way - All of a sudden my parallels guest machines could not access my NFS mounts from my mac. I use them to have quick access to my mac home directory from my FreeBSD dev install, for example.
The reason? It's complicated how I figured it out but - there is no more NetInfo. You used to have to set up NFS serving exports using the NetInfo Manager application. It used to be in /Applications/Utilities. I went to check my settings - and .... er.... it wasn't there.
So - upon investigation I read that netinfo has been completely removed from Leopard. That's a bad thing in that all the stuff I've done to get things working the way I wanted no longer worked. It's a good thing, however, in that you can for the most part use 'normal' unix-y things to get set up.
NFS, for example. If you want to do NFS exports from your mac, now instead of editing about 17 different netinfo elements, you just edit the /etc/exports file just like you do on any other Unix machine.
You don't need to enable nfs at boot because if you create an /etc/exports file, Mac OS X will see it on boot and automatically start nfsd.
Here's mine:
/Users -maproot=jayk -network 172.0.0 -mask 255.255.255.0
Also - for those of you familiar with nfs servers - Another interesting thing. Apple integrated mountd into nfsd. So you no longer need to start mountd in order to get your nfs mounts working. I don't know if this is a general trend or just something the UNIX folks at apple decided was a good idea. (Personally, I think it's, ahem, about damn time.)
FYI - after you create the exports file, you can restart your machine to get it to pick up the change, or you can just run:
sudo nfsd
That is all. Hope it saves someone some time.
DBIx::Class is a great interface to the database. It does a LOT of nice things for you - relationships, etc... but there are times when you just need a bit more functionality than DBIx::Class can figure out for itself. So you need to help it.
The two big ones I run into fairly often are - getting some data or some piece of information from a related table, but limited by certain requirements, or performing some action that requires additional data to perform the match. Most if not all of these things can be constructed by the clever usage of relationships and resultsets - but if it's something you need to do a lot, it makes sense to add it to your DBIx::Class classes.
You might at first glance think this is difficult - Sub-class the resultset or somesuch, try to get DBIx::Class to use it, etc... It's not actually that difficult at all.
First things first - If you are working with DBIx::Class' Schemas - your My::Schema::Foo class is your ResultSource class - or what essentially becomes your row object. So if you want to add a virtual column or accessor to an individual row - you can add the sub to your ResultSource object:
sub preference {
my ($self, $prefname) = @_; # $self is a row object herereturn $self->userattributes->search({ type => 'preference', name => $prefname })->first;
}
So now, assuming you have a user object $myuser - you could access it's preferences like so:
my $pref = $myuser->preference('keepmeloggedin');
Astute readers - especially those familiar with DBIx::Class would probably tell you that this should probably be part of the ResultSet. Ok... let's appease them. You can add this as sort of a virtual relationship. This is a bit more complicated, but again, not too difficult. You create a subclass of ResultSet:
Now you just go back to your Resultsource (My::Schema::Users) and add this:package My::Schema::Users::Resultset;
use strict;
use warnings;
use base 'DBIx::Class::ResultSet';sub preferences {
my ($self) = @_; # $self is a resultset herereturn $self->search_related('{ type => 'preference' });
}
__PACKAGE__->resultset_class('My::Schema::Users::Resultset');
*poof* Now you can access preferences from your User class's resultset, like so:
my $pref = myuser_rs->preferences->search({ name => 'keepmeloggedin' })->first;
# or
my @prefs = $myuser_rs->preferences->all();
See - that wasn't so hard, was it?
Catalyst has this great little widget, called RenderView. Ok. It's an Action. Basically what it does is sends your request off to be processed by whatever view it was that you use.
This almost always means forwarding off to the Template-Toolkit TT view, which will apply your templates and spit out a nice happy HTML response to the browser. Renderview is pretty much considered The Right Thing To Do(tm) for your average site... and as such it is how the fine Catalyst Tutorial recommends you do things.
But after you've been working with Catalyst for awhile, or maybe right away if you are a very AJAXy kinda guy, you realize that sometimes you want to go render template-y goodness, and sometimes you just want to dump out a JSON of some part of your $c->stash.
So what do you do? Most likely, your first attempt is to use some JSON module (JSON:XS, JSON, etc.) to convert your data to a string, and then stuff it into $c->response->body(). Since RenderView's docs tell you that if $c->response->body() exists, the view won't be run, that seems the logical thing to do. Totally sensible after reading the RenderView docs, Tutorial, etc.
You see, RenderView's documentation explains that it will forward to the first available view, or if you set the config setting 'default_view' will forward to that. And a peek at the code confirms this.
What you don't realize, unless you poke around a bit more and look at the source of RenderView, is that RenderView simply calls $c->view() to obtain the view to forward to.
I can already hear you saying "So what?"
Well, if you take a look at the docs for $c->view() - you realize that you can control what $c->view() returns quite easily by modifying the stash variable 'current_view'. This means that you can also, quite easily, get RenderView to forward off to an alternate view for any request, simply by setting $c->stash->{'current_view'} to the name of the view you want.
The practical upshot of all this is that you can use RenderView with multiple views very easily, and avoid all that mucking around with filling out $c->response->body(); manually. Instead, just set your 'current_view' to JSON, or whatever, and let RenderView do it's business.
I've been working with Catalyst for some months now and every so often... ok... just about every other day... I stumble upon or am shown some little bit of information that changes how I work with Catalyst.
Most of the time they are things that are in the docs, if you read them just right... or if you take a peek at the source, on occasion... but almost always, they are some little detail that doesn't look important, but turns out to enable something really cool.
I've been toying with the idea of throwing these up on a wiki or some other bit of online-documentation-ness - but I have never quite got around to it. Today I decided, after finding another little tidbit, I had to start documenting them somewhere. So that's why this is here.
I've tried blogs before... but I've never managed to keep up with them.... I feel like I have to write something important / etc... but we are going to try it again... with the proviso that this time, I'm just going to dump my brain here, and if folks find it useful, fabulous. Otherwise, at least I have a place to go look when I start thinking 'now how is it that I did that before.....?'
Anyway, enjoy.
Well, there's always the REST Action/Controller stuff too. Then you can dispatch to a View automatically by sending another content... read more
on Picking a view