WHY Rest

On Jan 4, 2008, at 2:26 PM, Anton J Aylward wrote:

I’m sorry if I seem confrontational; I’m just frustrated on a
number of
counts.

No worries. I wasn’t sure you could tell, and I want to help you
figure this out. I figured other people may have been having the
same reaction I was.

Surely I can’t be the only person so afflicted?

I hope not…you’re all the market for my eBook that I haven’t
written! :slight_smile:

Jeremy McAnally said the following on 04/01/08 03:33 PM:

No but you get a bunch of them generated for free.

Why not use them?

I could say ‘defensive programming’.
The named routes aren’t explicit, as I understand it.
A malicious user could experiment with dynamically generating routes.
A fat fingered typist (I’m one, so I know!) could use typos as routes
that are incompatible with other parts of the code.

I favour pushing back the checks. Routing seems a good place to say
what is and isn’t permitted.


Right now I’m having amnesia and deja vu at the same time. I think I’ve
forgotten this before.

Please, give us more detail regarding your experience! :slight_smile:

Your answer was very sensible and I would like to hear more from you.
I can see some of the benefits, but nothing REALLY interesting so
far…

Cheers, Sazima

On Fri, Jan 04, 2008 at 03:26:53PM -0500, Anton J Aylward wrote:

Over the past months I’ve asked more specific questions that are related
to this and not got any answers. None.

And as I say, I see plenty of “isn’t it great” postings in blogs but
very little that actually explains how to transform anything beyond a CRUD.

And it all seems to be coming out at once.

Surely I can’t be the only person so afflicted?

You are not alone. I have not been particularly impressed with REST as a
design paradigm for anything other than web services. While there are
certainly advantages to being able to create web services simply and
easily, I do not believe that good URL design for web services is the
same
as good URL design for user-facing sites. Conflating RESTful web
services
with good user interface doesn’t make sense to me.

I might feel differently about it if the class of webapps I develop
leaned
more toward Twitter or the like, but I typically create custom web
applications for nontechnical clients. There are requirements involving
how
the site is laid out and how it feels to be a user, and no concern about
web services.

I’d like to hear some compelling arguments about why RESTful Rails
development matters even if web services are completely off the table,
but
so far all I’ve heard is about how thinking of things as resources makes
for a nice design, which I’m not buying (see above).

–Greg

Use it or don’t. Nobody’s forcing you to. In fact, I dislike a lot of
the
Rails REST stuff, having done Rails for 3 years now. It’s easy to get
stuck
in your ways. Fact of the matter is that you have to make money and
progress. If what you have works, great. Investigate RESTful
architecture
for a future app.

Here’s how REST makes sense though, and this is NOT made clear by Rails:

Resources are NOT models.

I built a simple system to control the lights in my house. I did it with
REST. I ended up with two resources:

a Unit, which is the resource to manage the creation, deleetion and
modification of the X10 devices in my house.

When the time came to actually turn on a light switch or turn it off, my
first instinct was to add the following code to the Unit controller:

def on
@unit = Unit.find_by_id(params[:id]).on!
end

def off
@unit = Unit.find_by_id(params[:id]).off!
end

But after thinking about it, what I’m doing is changing the STATE of
the
unit. Therefore, it made more sense to have a State resource.

Changing the state is an Update, and Updates, according to REST should
be
PUT requests, not GET requests, as I was doing.

So I made a nested resource

map.resources :unit do |u|
u.resource :state # singular resource here cos I don’t need to list
them.
end

My state controller now had a method like this:

params[:value] can be “on” or “off” or “dim” or “brighten”

params[:amount] can be 0 to 100 and is used with “dim” or “brighten”

def update
@unit = Unit.find_by_id(params[:unit_id])
@unit.change_state(params[:value], params[:amount]) # amount is for
dimming.
end

Notice how the state resource changed how I implemented the code to
manipulate the light? Interesting stuff.

This also made me realize that the show action (get) could tell me the
current state of the light.

Already I have less complicated controllers, though I have more.

That’s just my .02. :slight_smile: I did a fun project to learn more about how REST
can
help me design things. I can share some code if anyone cares.

Gregory S. said the following on 04/01/08 04:11 PM:

Surely I can’t be the only person so afflicted?

You are not alone. I have not been particularly impressed with REST as a
design paradigm for anything other than web services. While there are
certainly advantages to being able to create web services simply and
easily, I do not believe that good URL design for web services is the same
as good URL design for user-facing sites. Conflating RESTful web services
with good user interface doesn’t make sense to me.

Good point.
As in “I wish I had said that”.
Things like games and wikis ARE the user interface, in many ways.

I might feel differently about it if the class of webapps I develop leaned
more toward Twitter or the like, but I typically create custom web
applications for nontechnical clients. There are requirements involving how
the site is laid out and how it feels to be a user, and no concern about
web services.

Yes, that applies to Wikis, and to the games I’ve seen and used.

I’d like to hear some compelling arguments about why RESTful Rails
development matters even if web services are completely off the table, but
so far all I’ve heard is about how thinking of things as resources makes
for a nice design, which I’m not buying (see above).


Expecting life to treat your fairly because you are a good person is
like expecting an angry bull not to charge because you are a vegetarian.
– Shari R Barr

On 04 Jan 2008, at 21:49, Anton J Aylward wrote:

I could say ‘defensive programming’.
The named routes aren’t explicit, as I understand it.
A malicious user could experiment with dynamically generating routes.
A fat fingered typist (I’m one, so I know!) could use typos as routes
that are incompatible with other parts of the code.

I favour pushing back the checks. Routing seems a good place to say
what is and isn’t permitted.

All of this has nothing to do with REST. Basically what REST does
(and I’m going to simplify things a bit), is express your public
model and relationship structure in the url. In essence, REST doesn’t
even dictate how URLs have to be formed, it’s a Rails convention to
do it the way it’s done.

I like my urls to reflect (part of my) model structure in a logical
way. It guides you in where to put your methods, e.g. if it has to do
with manipulating and article, i should put it in the articles
controller. Having the basic crud operations use a convention is a
nice bonus. Some people like to structure their controllers logically
into their views structure (e.g. project_summary, project_details, …
controllers for each tab in the projects section)

Your comment about a malicious user is something I really can’t get
my head around. In a dynamic web application, you always have a
certain logic in your urls. If your security issues have to do with
one user entering someone else’s account, there’s something very
wrong in your controller code, you should check if a user has access
to something instead of using cryptic urls hoping they won’t be
reverse-engineered. If you want to avoid scraping of your data, it’s
up to you to put appropriate measures in your controller to avoid
this (or better yet, use something like fail2ban to scan your http
logs for this kind of activity). I expect my REST urls to be logical,
that’s the whole point.

Programming using Rails (or any framework, but especially Rails with
its convention over configuration) is all about using the convention
that is laid out for you. Following the convention will save you
time, require less coding and make your code nicer to work with (both
for you and other people who also know the framework). Using the
restful conventions also opens a few doors to things like an API with
minimal extra coding, and never say never (more and more web
applications benefit from either using or providing an api, so even
if you don’t plan it now, it’s bound to come up one day). Converting
an existing application on the other hand has to be seen in
perspective. I will gradually introduce restful aspects in our
existing apps if i work on them, but converting a five month project
to rest just for the sake of it isn’t necessary.

Best regards

Peter De Berdt

On 04 Jan 2008, at 22:11, Gregory S. wrote:

I’d like to hear some compelling arguments about why RESTful Rails
development matters even if web services are completely off the
table, but
so far all I’ve heard is about how thinking of things as resources
makes
for a nice design, which I’m not buying (see above).

Since a lot of us seem to make a living out of this:
following as much of the convention as possible => less code => less
time => more productivity => more income.

One of our apps already uses a RESTful controller structure. It has
been a joy developping it, and when we got a new developer in on the
project, he immediately knew his way around. All of our apps are
custom apps for nontechnical clients, using REST hasn’t been a
problem at all (even if a lot of different “resources” were on one
single page). It does happen that the index method isn’t defined for
the moment (or just provides a quick @all_records.to_xml method), but
creating records, updating them, … are things you have to do anyway.

The hardest thing about it all is getting yourself to think outside
of your comfort zone and try to get into a new way of thinking. We’ve
done it, and for the most part, the whole REST thing just works, and
better than I ever expected.

Saying you’ll never need an api, is very dangerous. One of our
clients bought himself a very specialized application that would
benefit from pulling some of the data from our application. Their
supplier contacted us, we said we could provide an api very quickly
(he couldn’t, they would have to look into soap, make an analysis, …)
and explained the REST XML interface, added it to the application in
just half an hour (only the parts that needed to be exposed, but
still) and pleased our customer by not charging anything and tell him
it would be part of the support contract. It was so easy to do and
since we were the ones who could provide the api in the shortest
possible time with minimal effort, we could easily dictate it.

Best regards

Peter De Berdt

On Jan 4, 2008 4:26 PM, Brian H. [email protected] wrote:

When the time came to actually turn on a light switch or turn it off, my

But after thinking about it, what I’m doing is changing the STATE of the
unit. Therefore, it made more sense to have a State resource.

help me design things. I can share some code if anyone cares.
YEP! It’s not so much the url structure as the view of controllers as
resource controllers that’s important.

I got the same kind of epiphany from building one or two NEW
applications in rails 2.0 using rails view of restful design. It’s
one of those paradigm shifts that you have a hard time getting until
you do.

And I think that the epiphany is more likely to come from trying a new
fairly simple app using REST than by struggling through converting an
existing one. After the epiphany you’re much more likely to
understand what such a conversion really entails and how to do it
successfully.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On Jan 4, 2008 4:42 PM, Anton J Aylward [email protected] wrote:

I need to
understand the HOW to convert (or redesign). That’s what I’m seeking to
find out. And its why I’m frustrated by people simply telling me that
RESTfulness is a good thing.

As I just tried to point out in a recent reply to this post, it’s
probably better to learn how to first design using restful principles
for a simple new app before trying to re-design an existing app.

One small starting point might be to really understand the differences
between code generated by the the acts_as_authenticated and
restful_authentication plugins. Although that’s probably too small an
‘app’ to demonstrate the benefits of going from a few complex
controllers to more but much simpler ones.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Clearly this is a book asking to be written. That it hasn’t yet
appeared tells me that not many people (or at least not the right
ones) have a strong enough and solid grasp of it to write that book,
even if they personally know that it’s a useful idea.

In the software development race I’m a tortoise. I plod along until
the next step has been clearly explained by one of the smart hares who
have figured it out. So while I feel a tinge of guilt that my app is
not RESTful and my controllers fat, it’s not yet enough to get my
tortoise-behind to make the change.

And I don’t worry that my current application will later seem
antiquated and in need of a massive rewrite - every program I’ve ever
written could benefit from a rewrite, and I expect that to always be
true for me, and usually true for almost everybody else as well.

Jeremy McAnally said the following on 04/01/08 12:01 PM:

You don’t have to. You can have a search method on WikiController.
Nothing is stopping you.

Nothing is stopping me making system calls to custom C-code either, but
that’s not the point.

I’m trying to ask HOW I can re-structure things to take advantage of
REST. I’m repeatedly told its ‘good for you’ but short on the HOW.

Lots of the hints don’t make sense. A search method in the
WikiController could just as easily be a web service.

You go on to say

You’re completely missing the point of REST.
Yes, and its not the benefits I’m asking about, its the HOW.
Not the technical HTTP level how, but the code organization how.

And yes, I’ve read a lot about it and its stirred my interest, but its
still not telling me anything I can see how to USE. And by ‘use’ I mean
how to structure my code design to make sense and make use of it.

Because replacing what is now a method with a controller doesn’t make
sense - not to me, and not unless there is some advantage that you guys
see that I don’t and hasn’t been stated. And thinning down the
WikiController isn’t the advantage 'cos all the code is in
‘lib/search.rb’.

Let me give an example of what I mean by the HOW.
A blog, sorry can’t find it in my bookmarks quickly, suggested a skinny
controller full of ‘def action end’ and the code in the models views and
helpers. Well I managed to make one with all the code in the helpers.
Lots of DRY; the helper was really a ‘library’ for the ‘calls’ in the
views.

The examples of RESTfulness I’ve seen, with the exception of ‘restful
authentication’ (and questions about that have gone unanswered) all seem
to focus on CRUD and the kind of routing I very much DO NOT want to use.
They really do not communicate any advantage. But so what; I’ve seen
code fragments that show Perl and PHP outperform Ruby - perhaps they do,
in fragments, but at the level of whole applications where the code is
in Ruby-idioms rather than merely translating Perl, then Ruby performs
at least as well as Perl.

I had to learn the Ruby idioms, and now I prefer Ruby to Perl. So I can
accept it when Jeremy says he can write RESTful apps fluently.

What I don’t see is the HOW for anything but the basic CRUD.

Suppose I do that ‘SearchController with one method’ change, and work
though the changes to the routes (!?!). What do I do next? I can’t
keep coming back here and asking ‘what do I do next’. I need to
understand the HOW to convert (or redesign). That’s what I’m seeking to
find out. And its why I’m frustrated by people simply telling me that
RESTfulness is a good thing.


Genius may have its limitations, but stupidity is not thus handicapped.
Elbert Hubbard

Anton A. wrote:

What I don’t see is the HOW for anything but the basic CRUD.

You keep harping on “basic CRUD.” As if “basic CRUD” applications cannot
be complex.

It might help you to watch this video of DHH explain his new-found love
for CRUD:

Also, I thought Brian H. did a pretty good job of explaining the
elusive “how.”

Post: http://www.ruby-forum.com/topic/137572?reply_to=612281#612265

I’ll reiterate what I find to be his most important part: Resources are
not models.

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.

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.

That’s REST.

I think someone else in this thread mentioned that a single resource
doesn’t have to be restricted to one model. 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. Remember:
resources are not objects.

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.

See this pod cast for more on that:

Hope that helps answer the “how” portion of your question.

  • Daniel

On Saturday 05 January 2008, Daniel W. wrote:

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.

I don’t see the problem with searching at all and therefore may be blind
for what this solution offers, but I can’t imagine why I would model(!)
searching as creating a resource.

What’s wrong with

GET /clients?firstname=John&lastname=Doe

and handling it in ClientsController#index?

Michael


Michael S.
mailto:[email protected]
http://www.schuerig.de/michael/

Daniel W. wrote:

It might help you to watch this video of DHH explain his new-found love
for CRUD:

Oops, here’s the video:

  • Daniel

Michael S. wrote:

On Saturday 05 January 2008, Daniel W. wrote:

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.

I don’t see the problem with searching at all and therefore may be blind
for what this solution offers, but I can’t imagine why I would model(!)
searching as creating a resource.

What’s wrong with

GET /clients?firstname=John&lastname=Doe

and handling it in ClientsController#index?

Interesting. I never said there was a problem. And there’s certainly
nothing “wrong” with your approach.

Some things are better learned through experience. For me, REST was
certainly one of them. Perhaps the same is true for you.

At this point I’d strongly suggest that if you really want to
understand the how and why, you do it for yourself.

Obviously I hope you try the RESTful lifestyle and love it, but if you
don’t, no hard feelings. =)

  • Daniel

On Jan 5, 2008 8:21 AM, George B. [email protected] wrote:

Clearly this is a book asking to be written. That it hasn’t yet
appeared tells me that not many people (or at least not the right
ones) have a strong enough and solid grasp of it to write that book,
even if they personally know that it’s a useful idea.

Surely such a thing would be a tale of epic proportions, equivalent to
the
Lord of the Rings trilogy and the Chronicles of Narnia combined. Well,
that’s how complicated some people think it is.

In truth, restful routing is plain and simple. It’s like those books you
wrote when you were a kid in kindergarten that if a book critic were to
read
them he would jab his eyes out with a pen.

For this example I’m going to use a personal favourite: a forum system.
It’s
small enough to not be overwhelming, yet large enough to explain how
restful
routing should work (and generally why you should use it).

It all starts with the good 'ol config/routes.rb file. In here is where
all
the nice little routes live, from map.root all the way down to the
map.connect ‘:controller/service.wsdl’, :action => ‘wsdl’ that many
people
still leave in their routes file, thinking that if they remove it the
entire
world would collapse upon itself into one small quantum singularity. In
here
you’d place something similar to:

map.resources :forums, :has_many => :topics
map.resources :topics, :has_many => :posts
map.resources :posts

Not running on Rails 2.0? Then this is the code you want:

map.resources :forums do |forum|
forum.resources :topics, :name_prefix => “forum_”
end

map.resources :topics do |topic|
topic.resources :posts, :name_prefix => “topic_”
end

map.resources :posts

This defines routes like:
/forums/1 ← Show a forum
/forums/1/topics ← Index action for a single forum
/forums/1/topics/1 ← showing a single topic
/topics/1 ← Same thing
/topics/1/posts/ ← I would imagine this would do a similar thing to
/topics/1
/topics/1/posts/1/edit ← Allows you to edit a single post
/posts/1/edit ← Same thing

Now to define something like this without the magic of restful routing,
one
would have to be clinically insane:

map.connect “/forums/:id”, :controller => “forums”, :action => “show”
map.connect “/forums/:forum_id/topics/”, :controller => “topics”,
:action =>
“index”
map.connect “/forums/:forum_id/topics/:id”, :controller => “topics”,
:action
=> “show”
map.connect “/topics/:id”, :controller => “topics”, :action => “show” ←
Does this look familar to /forums/:id?
map.connect “/topics/:topic_id/posts”, :controller => “posts”, :action
=>
“index”
map.connect “/topics/:topic_id/posts/:id/edit”, :controller => “posts”,
:action => “edit”
map.connect “/posts/:id/edit”, :controller => “posts”, :action => “edit”

And this is only the tip of the iceberg!

Seeing a pattern here? Restful routing gives you a whole heap of cool
stuff,
namely the 7 core methods that I’ll cover right after the models.

A forum system has the following tables: forums, topics, posts and
users,
and the models would look something like the following:

class Forum < ActiveRecord::Base
has_many :topics
has_many :posts, :through => :topics
end

class Topic < ActiveRecord::Base
has_many :posts
belongs_to :forum
belongs_to :user
end

class Post < ActiveRecord::Base
belongs_to :topic
belongs_to :user
end

class User < ActiveRecord::Base

has_many :topics
has_many :posts

def to_s
login
end
end
The fields don’t matter, but throughout the tutorial I make reference to
@
forum.name or something similar, so we’ll assume forums has at least a
name
field. We’ll assume post has a text field and users has a login field.

That’ll give you some idea of how the system works: Forum → Topics →
Posts.

In restful routing there are seven “core” methods (actions) that you’re
given for the controllers: index, show, new, create, edit, update,
destroy.
Each of these have a set request method on them, for example you can’t
GET
to the create, update and destroy actions and you can’t post to the
index,
new or edit actions. These actions work with these request methods:

GET: index, show, new, edit
POST: create
PUT: update
DELETE: destroy

“What the?! PUT & DELETE, where did they come from?”, I hear you cry!
These
are hacked into the calls for the appropriate action using javascript,
it
passes in one more parameter (_method) which is then handled by the
rails
code and depending on what method you called you will get the page you
were
looking for, or a routing error.

The forums controller could look like this:

class ForumsController < ApplicationController
def index
@forums = Forum.find(:all)
end

def show
@forum = Forum.find(params[:id])
end

def new
@forum = Forum.new
end

def create
@forum = Forum.create(params[:forum])
flash[:notice] = “You have created a forum!”
redirect_to forums_path
end

def edit
@forum = Forum.find (params[:id])
end

def update
@forum = Forum.find(params[:id])
@forum.update_attributes(params[:forum])
flash[:notice] = “You have updated #{@forum.name }”
redirect_to forum_path
end

def destroy
@forum = Forum.find(params[:id])
@forum.destroy
flash[:notice] = “You have deleted #{@forum.id}”
redirect_to forums_path
end

You’ll see here that I’ve twice made a call to redirect_to using the
argument of forums_path. Because we’ve defined map.resources :forums in
our
config/routes.rb file, it knows that we want to go to { :controller =>
“forums”, :action => “index” } and the best part is that we don’t have
to
keep trying { :controller => “forums”, :action => “index” } every time
we
want to go to that specific action, but instead we type forums_path.

I’ve also made a single call to forum_path, and I haven’t specified an
argument for it, so how does Rails know that I want to go to the forum
that
I just updated?

Rails will see that there’s an argument mission from the forum_path and
will
go looking for the @forum instance variable you’ve defined in your
controller. If you never defined one or defined it as something other
than
@forum, it will mention something about ambiguous routes and you’ll have
to
specify the variable.

Now what if you wanted to go to the new or edit action? Simple:
new_forum_path and edit_forum_path(@forum) will take you to the
corresponding actions. Remember that you don’t need to specify an
argument
for the edit_forum_path if @forum is defined. Inside these actions
you’ll
want to go further, you’ll want to create a new forum and update a
forum.

For the create action you could specify this for your form:

Rails 2.0:

form_for @forum do |f|

Rails 2.0 will see that @forum is a new record and link you the create
action.

Pre Rails 2.0:

form_for :forum, @forum, :url => forums_path do |f|

Prior to Rails 2.0 that checking wasn’t in, you’ll have to define your
own
link.

“B-b-b-ut”, you stammer, “you’ve linked to the forums index, right?
Isn’t
that what forums_path is?”

Well, yes and no. This has everything to do with the four request
methods
mentioned previously, because the form’s method attribute is “post”,
Rails
knows that if you’re posting to forums_path, you mean the create action.
And
now for the update action!

Here the form_for’s a little different (for Pre-Rails 2.0):

*Rails 2.0:

*form_for @forum do |f|

Again the same deal applies: Rails 2.0 knows that @forum is not a new
record, so it’ll link you to to the update action because it’s included
in a
form. This automatically specifies :html => { :method => :put } for
you.

Pre Rails 2.0

form_for :forum, @forum, :url => forum_path(@forum), :html => { :method
=>
“put” } do |f|

It knows to link you to the update action because of the method => “put”
we’ve specified.

Now lets escape from the confines of a single controller and bring the
topics controller into the mix. In the forum show action is where you
would
generally show all the topics for that forum, but for the purposes of
this
tutorial I will do it in the topics controller instead. This will have
something similar defined to the forums controller but personally I
would
define this for the controller:

class TopicsController < ApplicationController
before_filter :get_forum
def index
@topics = @forum.topics
end

#other actions

private
def get_forum
@forum = Forum.find(params[:forum_id]) if params[:forum_id]

end

The private call makes any method after it private, that means that if
you
were to try and access this method (without restful routing), it would
play
dumb. Personally I think something like this should be in-built to
Rails, if
you’re accessing a child object (topics) from a parent (forum) it should
automatically define @forum for you.

Because we’ve already defined the :has_many topics on map.resources
:forums,
the topic routes are already defined for us, so to view all the topics
for a
forum, before you would have to do define a route like this:

map.connect “/forums/:forum_id/topics/”, :controller => “topics”,
:action =>
“index”

and then calling it like this:

{ :controller => “topics”, :action => “index”, :forum_id => @ forum.id }

Instead you’ve already defined :has_many :topics, so instantly you’ll
gain
access to forum_topics_path. Again the wonderful Rails will realise that
you
want all topics for the @forum object and then direct you to
“/forums/1/topics/” through forum_topic_path. To edit a single topic,
you
could do edit_forum_topic_path as of Rails 2.0, or forum_edit_topic_path
prior to Rails 2.0. The first reads more like “edit this topic belonging
to
this forum” where the second reads like “in this forum, edit this
topic”.
Alternatively you could ditch the whole forum part out of the method
call
and just do edit_topic_path because we’ve defined map.resources :topics.

Throwing one more controller into the mix now, called posts_controller.
This
would be very similar to the topics controller but instead of get_forum
it
would have get_topic, modified correctly.

Now what if you wanted to add a custom action to posts_controller,
called
quote? This action would bring up a form with the post you were quoting
which would then send the information from the form into posts/new to
create
a new post:

In config/routes.rb:

map.resources :posts, :member => { :quote => :get }

The extra argument of :member indicates a hash of any further actions
and
their request methods you would like to be added onto singular posts.
You
can call these like all the other singular methods:
quote_post_path(@post),
for example. The request methods can be in string or symbol format, it
doesn’t matter.
def quote
@old_post = Post.find(params[:id])
@post = Post.new
@post.text = “[quote=‘#{@old_post.user}’]#{@old_post.text}[/quote]”
render :action => “new”
end

Here I’ve defined the old post only to get the text and the user’s name
from
it, and then we’re rendering the new view so we have the form.
Everything
from there on is taken care by Rails.

Now what if you want to define a new action to work with a group of
posts?
Well you define it like this:

routes.rb

map.resources :posts, :member => { :quote => :get }, :collection => {
:destroy_all => :delete }

Now if you wanted to destroy all posts for a topic, bar the first one,
with
an action like this (remembering @topic is defined in get_topic):

posts_controller.rb

def destroy_all
@posts = @topic.posts - @topic.posts.first
@posts.each { |post| post.destroy }
flash[:notice] = "All posts have been deleted.
end

You would link_to it like this:

link_to “Delete all posts”, destroy_all_topic_posts_path(@topic),
:method =>
“delete”, :confirm => “Are you sure you want to delete all posts from
this
topic?”

The :method => “delete” corresponds with the :delete_all => :delete we
specified in config/routes.rb.

That’s it for now. If it still isn’t clear how awesome restful routes
have,
then please state why, as I would love to know.


Ryan B.

Feel free to add me to MSN and/or GTalk as this email.

Hey Ryan, thanks for the interesting REST tutorial. You should really
get a blog / post that on a blog rather than on this forum. The
formatting on this forum is atrocious and I would really like to be able
to refer back to this later.

Daniel W. 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
Reclusive Geek: Peepcode's Restful Rails
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.


The whole art of teaching is only the art of awakening the natural
curiosity of young minds for the purpose of satisfying it afterwards.
Anatole France (1844 - 1924), The Crime of Sylvestre Bonnard

On Saturday 05 January 2008, Daniel W. wrote:

certainly one of them. Perhaps the same is true for you.

At this point I’d strongly suggest that if you really want to
understand the how and why, you do it for yourself.

Obviously I hope you try the RESTful lifestyle and love it, but if
you don’t, no hard feelings. =)

But you appear to suggest that my approach is somehow not RESTful. I’d
take exception to that and claim that, yes, what I suggest is
completely in line with REST. And it is my understanding that the
authors of “RESTful Web Services” (Leonard Richardson & Sam Ruby)
agree. I highly recommend that book.

Michael


Michael S.
mailto:[email protected]
http://www.schuerig.de/michael/