Tutorial - Creating a Global REST Controller

=========================================
Creating a Global REST Controller

Let’s imagine that you have an application that houses close to 400
controllers. Each of these controllers accesses a specific model that
contains normalized data. While there are a lot of tricks you can
perform for normalization, let’s assume that after you further normalize
and consolidate databases you still have 300 controllers left over.

Of these 300 controllers, half of them are composed of normal REST
methods, and the other half are comprised of normal REST methods and
special methods which perform specific actions.

This means that each of those controllers at a bare minimum could have
close to 80 lines of code.

Everyone talks about thin controllers. I’m going to show you a way to
create a Global REST controller that will make most if not all of your
controllers very thin.

Take a look at the code above and look closely at the Global REST
Controller.

Let’s pretend that you have a controller that manages pages, ie. a Pages
Controller. It’s comprised of only index, new, edit, show, create,
update, and destroy. No other actions.

By implementing a Global REST controller, you could place this in your
pages controller:

class PagesController < GlobalRestController
end

… and that’s all you need (2 lines of code)

In your index.html.erb view you would replace one instance variable
@pages with @objects and you are done.

Now then, going back to the old scenario I posted above, you could
effectively take 150 controllers with say 78 lines of code and reduce
11,700 lines of code down to … 300.

What could you do with your other 150 controllers?

class SomeOtherController < GlobalRestController

def some_custom_action
… etc.
… etc.
end

def some_other_custom_action
… etc.
… etc.
end

end

Your custom actions would be listed but you would automatically inherit
the other 7 rest methods automatically. No extra code needed.

What if you want to overwrite one of the REST methods with a custom REST
method of your own?

class SomeOtherController < GlobalRestController

def index
@pages = Page.find(:all, :conditions => ‘parent_id IS NOT NULL’)

respond_to do |format|
format.html
format.xml { render :xml => @pages }
end
end

end

You just simply place the REST method into your controller and it still
picks up the other 6 REST methods. You then keep the index.html.erb
page intact without @objects changes and you are done.

How well does this work?

I currently run a football statistics site that houses 75 controllers
and (66 of them) are part of a Global REST Controller mechanism. I have
had no issues whatsoever using it.

I hope this tutorial helps someone out. If you liked this tutorial, you
can check out a very lengthy tutorial I wrote yesterday on mailers and
observers here:

http://www.ruby-forum.com/topic/202316

Take care.

In a follow-up on your edit.html.erb and new.html.erb you could use
something similar:

Replace @page with @object. I’ve added a partial and a couple of
example forms for these as well in the gist posted above.

Very cool. I’m glad to hear it is working out so well for you Alpha…

Interesting tutorial. Thanks.

I found there are a couple of little problems. First, your index view
code has some extra closing round brackets, and then the destroy
action redirects back to the deleted object. I took a little while to
fork and update the controller code. Also made it a bit more DRY:

One question though, why wouldn’t you use, for example,
inherited_resources plugin for this purpose?

  • Aleksey

On Jan 19, 12:43Â am, Aleksey G. [email protected] wrote:

inherited_resources plugin for this purpose?

  • Aleksey

I don’t wanna speak for Alpha B., but straight plain inheritance is
a simple answer to a common problem…

Alpha B. wrote:

=========================================
Creating a Global REST Controller

Let’s imagine that you have an application that houses close to 400
controllers. Each of these controllers accesses a specific model that
contains normalized data. While there are a lot of tricks you can
perform for normalization, let’s assume that after you further normalize
and consolidate databases you still have 300 controllers left over.

Why would you ever have that many controllers in the first place? That
makes no sense.

Of these 300 controllers, half of them are composed of normal REST
methods, and the other half are comprised of normal REST methods and
special methods which perform specific actions.

This means that each of those controllers at a bare minimum could have
close to 80 lines of code.

What? No. An 80-line controller means you have too much logic in the
controller and not enough in the model.

Everyone talks about thin controllers. I’m going to show you a way to
create a Global REST controller that will make most if not all of your
controllers very thin.

Why not just use make_resourceful?

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

It seems like to create 300 ReST controllers via Rails Scaffolding or
make_resourceful, one would need to type all the specs for all the
tables into the Rails Scaffolding generator. If I am reading
correctly, one could use Global Rest Controllers on existing tables,
and those controllers would read the tables structures for themselves.

I work a lot with legacy tables, so I would dislike typing the
structure into the Rails Generator all the time. I don’t do that: I
use home-brew Scaffolding Generators that read the table structure,
like the old pre-Restful Rails scaffolding.

Anyway, could that be one difference?

Ron

Aleksey G. wrote:

Interesting tutorial. Thanks.

I found there are a couple of little problems. First, your index view
code has some extra closing round brackets, and then the destroy
action redirects back to the deleted object. I took a little while to
fork and update the controller code. Also made it a bit more DRY:

global_rest_controller.rb · GitHub

One question though, why wouldn’t you use, for example,
inherited_resources plugin for this purpose?

  • Aleksey

Thanks for that Aleksey, I had copied and pasted from an older
controller that was using not so polished code.

I very rarely use plugins in my app. I don’t like to use code that I
can’t control myself. I would rather find a plugin that is suitable,
dive into the code, learn from it, and create my own modified plugins.

This is just a very simple tutorial outlining to some newer folk how
they can create an inheritance template for their controllers.

I have my own private inheritance template for my models, which works
equally well.

Marnen Laibow-Koser
Why would you ever have that many controllers in the first place? That
makes no sense.

Your statement doesn’t make any sense. I’ll give you one answer before
you throw out the assumptions once again mate. You really should stop
doing that. My one application is comprised of:

4 separately run applications tied together on different servers.

On Jan 19, 2:58Â pm, Marnen Laibow-Koser [email protected] wrote:

I very rarely use plugins in my app. Â I don’t like to use code that I
can’t control myself. Â I would rather find a plugin that is suitable,
dive into the code, learn from it, and create my own modified plugins.

http://c2.com/cgi/wiki?NotInventedHere

I have the opposite philosophy. Â If someone has already written
something suitable, I see little reason to duplicate their effort.
Extend it, sure. Â Write something that’s a better fit for me, sure.

I find it a difficult one to call - while the above is true it’s
horrible find come rails upgrade time that the author has abandoned
the project. Lots of rails plugins are small one man things - I would
certainly hesitate to use a plugin unless either it has sufficient
backing/momentum that I can trust it will stay around or I understand
it enough that I could rewrite it if I had to.

See, the number of controllers is a UI issue. Â No matter how many types
of object you’re dealing with under the hood, if the user has to
navigate among 300 controllers (which, after all, are generally the
user-facing part of the app), then in 99 cases out of 100, I’d say you
need to refactor the UI or split up the app.

That is assuming these are end user facing controllers (as opposed to
ones for api clients). (and if the OP does indeed have 4 apps then
they have already split up the app)

Fred

Alpha B. wrote:

Aleksey G. wrote:

Interesting tutorial. Thanks.

I found there are a couple of little problems. First, your index view
code has some extra closing round brackets, and then the destroy
action redirects back to the deleted object. I took a little while to
fork and update the controller code. Also made it a bit more DRY:

global_rest_controller.rb · GitHub

One question though, why wouldn’t you use, for example,
inherited_resources plugin for this purpose?

  • Aleksey

Thanks for that Aleksey, I had copied and pasted from an older
controller that was using not so polished code.

I very rarely use plugins in my app. I don’t like to use code that I
can’t control myself. I would rather find a plugin that is suitable,
dive into the code, learn from it, and create my own modified plugins.

http://c2.com/cgi/wiki?NotInventedHere

I have the opposite philosophy. If someone has already written
something suitable, I see little reason to duplicate their effort.
Extend it, sure. Write something that’s a better fit for me, sure.

But by just saying “I don’t like plugins”, you’re making yourself a lot
of extra work for no good reason.

This is just a very simple tutorial outlining to some newer folk how
they can create an inheritance template for their controllers.

I have my own private inheritance template for my models, which works
equally well.

Sure.

Marnen Laibow-Koser
Why would you ever have that many controllers in the first place? That
makes no sense.

Your statement doesn’t make any sense.

Of course it does. No matter how many models your app has, I can’t see
why a well-designed app would ever need to expose 300 different types of
resource – which is essentially what controllers are about.

I’ll give you one answer before
you throw out the assumptions once again mate. You really should stop
doing that.

I’m not assuming anything in particular, so this is not relevant.

My one application is comprised of:

4 separately run applications tied together on different servers.

Then it isn’t one application. Or it’s one application run clustered.
In neither case do I see this making the slightest difference to the
number of controllers.

See, the number of controllers is a UI issue. No matter how many types
of object you’re dealing with under the hood, if the user has to
navigate among 300 controllers (which, after all, are generally the
user-facing part of the app), then in 99 cases out of 100, I’d say you
need to refactor the UI or split up the app.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Thanks again guys for your input. As a point of clarification…

My app(s) contain a combined 63 controllers across 4 applications, so if
you wanted to divide that number by 4 you have less than 16 controllers.
Many of these controllers are “not” client-facing controllers. I have
really 6 client-facing controllers in my entire combined app cluster.

The point of this thread was how to reduce code duplication across
multiple controllers. I threw out an absurd amount of controllers to
make a point of reference.

As for the topic on plugins, I’m in agreement with Fred on this. I have
experienced on quite a few occassions upgrading to a newer version of
rails only to find out the author abandoned the project and I had to dig
into the code and fix it all myself.

There are plugins that I do use that I do not create or modify myself
that have substantial backing. RedCloth is an example of this.
Restful_Authentication is another.

Frederick C. wrote:

On Jan 19, 2:58Â pm, Marnen Laibow-Koser [email protected] wrote:

I very rarely use plugins in my app. Â I don’t like to use code that I
can’t control myself. Â I would rather find a plugin that is suitable,
dive into the code, learn from it, and create my own modified plugins.

http://c2.com/cgi/wiki?NotInventedHere

I have the opposite philosophy. Â If someone has already written
something suitable, I see little reason to duplicate their effort.
Extend it, sure. Â Write something that’s a better fit for me, sure.

I find it a difficult one to call - while the above is true it’s
horrible find come rails upgrade time that the author has abandoned
the project.

That’s certainly true.

Lots of rails plugins are small one man things - I would
certainly hesitate to use a plugin unless either it has sufficient
backing/momentum that I can trust it will stay around or I understand
it enough that I could rewrite it if I had to.

Also a good point. I mention make_resourceful because it doesn’t seem
to be going away, and Hampton Catlin is certainly not going away (well,
unless he pulls a _why).

See, the number of controllers is a UI issue. Â No matter how many types
of object you’re dealing with under the hood, if the user has to
navigate among 300 controllers (which, after all, are generally the
user-facing part of the app), then in 99 cases out of 100, I’d say you
need to refactor the UI or split up the app.

That is assuming these are end user facing controllers (as opposed to
ones for api clients).

True, although what API you expose is sort of a UI issue. In any case,
an API so bloated that it exposes 300 controllers is scary. :slight_smile:

(and if the OP does indeed have 4 apps then
they have already split up the app)

Right. In which case it’s not one app and, at least to me, it doesn’t
mean much to count the total number of controllers across the 4 apps.

But on reflection, I see that the original point was code duplication,
so from that point of view it may make sense. Hmm.

Fred

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

(Of course, those happen to be two of the most broken plugins in common
use…RedCloth, at least for a while, had sort of stagnated (is that
still so?), and restful_authentication is based on generated crap code,
and should be abandoned completely in favor of Authlogic.)

RedCloth has gotten better and there are multiple versions of the gem
with some being more updated than others. I try to find the people that
use it the most and I use that gem or compile the binaries myself.

I liked restful authentication when I first tried it out but I have to
agree with you that it’s missing a lot of features that I personally
would like to have in an authentication system. I’ve had to tailor it
to fit my needs. I’ll take a peek at Authlogic and see what it has to
offer.

Not to get off topic, but what do you personally like about Authlogic,
or some of the big features?

Thanks mate.

Alpha B. wrote:

Thanks again guys for your input. As a point of clarification…

My app(s) contain a combined 63 controllers across 4 applications, so if
you wanted to divide that number by 4 you have less than 16 controllers.
Many of these controllers are “not” client-facing controllers. I have
really 6 client-facing controllers in my entire combined app cluster.

Ah, that makes more sense. :slight_smile:

The point of this thread was how to reduce code duplication across
multiple controllers. I threw out an absurd amount of controllers to
make a point of reference.

OK. It seemed like you were talking about an actual case. Sorry for
misunderstanding.

As for the topic on plugins, I’m in agreement with Fred on this. I have
experienced on quite a few occassions upgrading to a newer version of
rails only to find out the author abandoned the project and I had to dig
into the code and fix it all myself.

I’ve only experienced that very rarely. Then again, I try not to choose
plugins that look stagnant in the first place.

There are plugins that I do use that I do not create or modify myself
that have substantial backing. RedCloth is an example of this.
Restful_Authentication is another.

(Of course, those happen to be two of the most broken plugins in common
use…RedCloth, at least for a while, had sort of stagnated (is that
still so?), and restful_authentication is based on generated crap code,
and should be abandoned completely in favor of Authlogic.)

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]