Daniel Waite said the following on 04/01/08 08:03 PM:
I'll look up the video when I get my codecs working, but ...
I'll reiterate what I find to be his most important part: Resources are
_not_ models.
OK, not a problem. See below.
Imagine a collection of clients. We can create, read, update and delete
those resources (forget that you may have an actual client model as
well).
But what about searching for clients? That doesn't seem to fit the CRUD
model. Except it does.
For some values of 'fit'. See below.
If we twist our brains, we might come up with a ClientSearches resource.
Notice I said resource. That means another controller. No new models
though. Just a different way of looking at our model.
With ClientSearches in our brains, it _does_ make sense to CRUD it. When
we perform a search we are _creating_ a new search.
No.
You're confusing an artefact of the language with the abstraction.
In Ruby you have to deal with classes and hence you have to do a 'new'.
If you look at the code base for TWiki you'll see they've made
everything an object. To do a save you hand the string to an object
that is the instance of the StorageManager rather than writing to a
file. There are lots of such objects. The startup code is full of
$this->{part} = new TWiki::Part( $this )
as the various parts (implemented as objects) are instanced and
references to them kept in one big 'context' object, and all further
operations indirect though that.
It makes the code ugly. Well uglier than Perl code needs to be. But
that's Perl and objects for you.
I point this out because a language in which each 'thing' is an object
can't be used (aka its methods) until you create an instance of that
object. Ruby is such a language. It doesn't matter if the Search class
is a controller or a library, you still end up doing
s = Search.new( ... )
You've made a 'virtue out of a necessity'. Of course we're creating a
new search. But that has nothing to do with a resource being a design
decision.
I've seen the likes of 'search' implemented many ways. With Ruby's
light-weight objects it makes sense to load stuff at create time.
In TWiki's Perl, there's just the one search engine for each context
(aka thread) so its completely parametrized when its invoked:
$this->{search} = new TWiki::Search( $this ) # 'new' per session
.....
$text = $this->{session}->search->searchWeb( .. huge argument list ...)
Now THAT is a design decision. That it is ugly and ungainly is an
artefact of the language!
So whether the design decision loads up at the time the search object is
instanced or when its method is invoked IS a design decision. You can
see a permutation on this with the use of the BruteMatch method used for
searching in the Socks-Wiki, another Ruby Project from before Rails.
The loading of the patterns and the search space are very spread out and
obscure, since, one again, the single engine is instanced into a context
object.
But unless you call the instantiation of the search object a
'create/INSERT//Post', and its going poof! when it goes out of context
and becomes a candidate for the garbage collector as a
'delete/DELETE/Destroy' there's not going to be a lot of methods. As
far as I can see a 'new()' and a 'do_the_search()'. No CRUD in it.
Or did I blink and miss something?
That's REST.
See below.
I think someone else in this thread mentioned that a single resource
doesn't have to be restricted to one model.
Indeed. No argument, but that's a design an decision that is
independent of REST. My WikiController handles both the Web and the
Topic models in one gulp. If you look at Instiki, it does the same, and
updates other models that keep track of links and cross references.
While I'm mentioning it, would you call Instiki 'RESTful'?
If not, why not, and if so, why so.
If I have an Account
resource, I could use the show method to display a Company object, all
their Client objects, and maybe even some Contact objects.
If I'm looking at a page in an address book the Person might have any
number of addresses and phone numbers. (Don't you hate the things like
ACT where there's only a fixed number of slots for phone numbers because
they are part of the Person record and not a separate 'has many' object.)
Remember: resources are not objects.
Or at least they need not be. See 'restful authentication'.
Also, REST is not limited to CRUD. You can easily define other actions
in your controllers provided the actions they carry out are respective
to their HTTP method. In Rails 2 (possibly lower versions, not sure) you
can specify a new custom route onto a map.resources command.
Hope that helps answer the "how" portion of your question.
No, if anything it leaves me more confused than before, for the simple
reason I'm doing most of that without anything looking what I've seen
described as RESTful.
My wiki has a controller that has no model behind it and my models don't
have corresponding controllers. The Wiki is the resource the user sees.
The webs and the topics in them aren't resources, they are content.
In fact I get puzzled why forums and blogs do nested routing.
If you look at the URL
http://reclusive-geek.blogspot.com/2006/11/peepcodes-restful-rails.html
there isn't a month controller in the year controller. The URL is
user-friendly, its not
/year/2007/month/11/post/peepcodes....
And since there's a lot of 'old code' that works this way its not a
feature of RESTfulness.
In fact the only controller in my wiki that that has a model behind it
or model with corresponding controller is the 'User' and that's
'restful authentication' and that has
new create activate
suspend unsuspend destroy
purge change_password forgot_password
reset_password find_user
And a deal of that was pasted in from 'acts_as_authenticated' and 'state
machine' as you can see. And I kept the named routes as well. So I'm
not bothered by 'beyond the CRUD'. Is this a 'fit the CRUD model'? I
wouldn't call it that. Not without squinting. I could remove the
'destroy' and 'purge' since there's no button on any of the views that
leads to them and its not part of the functionality. A user gets
suspended but the record is still there so that authorship can be
attributed. That's part of being a Wiki. I could delete those methods;
perhaps T should :-). And the login process don't offer a 'find' to the
user interface. You have to know the name or the activation code. So
its C-U-.
I have a (single) custom route for the wiki that doesn't involve any
'nesting' as there is only one relevant controller - the WikiController.
See above and previous postings. The 'restful controller', however,
uses lots of custom routes.
Sorry if this seems argumentative, but I'm trying to explain why I'm
saying "no it doesn't help explain the HOW'. Either I'm doing RESTful
design (and always have) without RESTful routing and without knowing it,
or there's something I'm not getting here.