ActionController for Resources

Ok guys, its been a while since I've posted here. I don't think I've
had a Rails feature added since the hash-as-conditions patch from
forever and a half ago. I've been busy building apps and working on
new languages. Oh, well and working on make_resourceful too. I'm not
sure how familiar you guys are with make_resourceful but its a tank of
an abstraction that helps "ninjas" to build really abstracted code for
their resource based controllers.

Ever since the beginning, I knew that m_r wasn't right for Rails core.
It was best as a plugin. There was a ton of magic and mystery in it...
and frankly. It did too much. Lots of people use it today and enjoy
it, but it requires *learning* a lot of new stuff to use it
effectively.

I've been getting a lot of emails recently asking "what's next" for
m_r... and so it got me thinking. What _is_ next? m_r has solved my
issues with app development for 90% of my controllers for the past
year and a half. So, should I really add anything?

Then, it hit me. Why not take the lessons I've learned from being a
professional rails developer who has done (GASP) 14 production Rails
apps with resources and come up with something a lot less ninja, and a
lot more core.

So, here is the idea. One of the best things that m_r does is give you
nice accessor methods for the resources you are currently working
with. I noticed that in most of my controllers I was repeating lines
like this..... "User.find(params[:user_id]).messages.find(:all)".
Over, and over, and over, and over again. Even with the create method
for that "message", I'd want to scope it,because I'd want the magic of
having an automatically assigned user_id on the message (or, I'd just
be lazy and do a second line). Anyhow, that's the least DRY part about
doing a resourceful controller. Accessing the stuff you want.... over
and over and over.

So, here is my proposal: http://pastie.org/230474

The way its structured is first is a really simple example. Followed
by two complex examples, THEN followed by those last two examples in
their *explicit* form. Basically, the explicit form is the code that
would be automatically added by the ::load call.

Basically, you call the class method "load" on ActionController::Base
and pass it an array of classes or symbols (read the code there to
figure out the symbol bit... I'll just stick to classes here). The
last arguement to it is your resource. And the ones before it are the
scopings.

If I say "load User"... it builds four methods.... #user, #users,
#build_user, and #update_user. Read the explicit versions before to
get the gist of what each one of them does.

The problem with m_r and other proposals are that they assume too
much. However, I think that this is just the right mix. I'd be
surprised to find a resource controller that couldn't be cleaned up by
this abstraction.

Too much magic? Not really. Think of it like belongs_to for your
controllers. No one complains that belongs_to "creates" (I know, not
literally) methods on your AR models.

I'd love feedback on this. If its not right for core, I'll just make a
plugin and go about pimping it. If it seems like something that MIGHT
be interesting for core, then I'll fork and fiddle.

Thoughts?

-hampton.

+1

I'd love feedback on this. If its not right for core, I'll just make a
plugin and go about pimping it. If it seems like something that MIGHT
be interesting for core, then I'll fork and fiddle.

I think there's definitely something to this, at the very least it's
worth investigating what kind of functionality we can add in. For a
while now there's been talk about how there really should be some
concept of resources that you could introspect to do these kind of
useful things.

Have a look at Resources Controller (RC) plugin, which is a pretty
mature and functional set of functionality for getting the relevant
resources for a controller. RC is strong -I gave up my own solution
to adopt RC (and contribute a bit). Ian White, the author, has really
kept it going.

http://groups.google.com/group/resources_controller?hl=en

Also, see my blog post on how Rails routing could help the cause
without having to pick (yet) a particular implementation::

http://cho.hapgoods.com/wordpress/?p=151

"Full Circle REST" is where it's at.

-Chris

Also, see my blog post on how Rails routing could help the cause
without having to pick (yet) a particular implementation::

http://cho.hapgoods.com/wordpress/?p=151

"Full Circle REST" is where it's at.

Definitely, and I think we've discussed this previously on #rails-contrib?

I'm not necessarily sold on having the concept of the 'resource'
you're looking at tied so tightly to routes. Perhaps there's another
class we should have which is available on the request?
request.resource or something with the necessary bits and bobs to
introspect successfully.

I think the best way forward is for the authors of the relevant
plugins (m_r and RC) to figure out if there's a subset of
functionality which they could share, and then figure out what changes
we'd need to make to rails to enable that functionality, or if we
should adopt it ourselves.

My point with all of this is to massively strip down the functionality
that is available in the plugins and just have an extremely simple
interface for the most basic, basic resource facilities in a
controller. Then, build from there if the need arises.

-hampton.

My point with all of this is to massively strip down the functionality
that is available in the plugins and just have an extremely simple
interface for the most basic, basic resource facilities in a
controller. Then, build from there if the need arises.

Sounds great to me :slight_smile:

There's also my plugin resource_controller - a little naming collision
there, but nonetheless...

All three of these plugins have a decent amount of traction, and
something to offer. I do think that it makes sense for the three of us
to sit down, and brainstorm over what we can do to add this to rails.
Then, our respective plugins can use that as a foundation for building
magical abstractions on top of.

I like Hampton's proposal - I think it covers a lot of cases, while
remaining relatively neutral in terms of what it expects.

The only things I'm not clear on is how it would cover polymorphism,
or cases where the association has a non-standard name. Sure, you
could override all the methods that it 'generates', but that would be
a pain, and not very DRY. It'd be nice to expose some methods like m_r
and my r_c do that would allow you to define the way objects,
collection, and associations are loaded for each level.

For polymorphism, sticking with Hampton's syntax, we'd end up with:

load [User, Project], [Project], [Account, Project]

.. which I'm not crazy about. I think something like:

resource_for Project # could be inferred from controller name if std
belongs_to x, y, [z, a] # args here are x, OR y OR z, a

...potentially replacing belongs_to with parents, or another
keyword...

Lastly, I personally dislike the idea of controller actions being tied
to routes, as they are in resources_controller. We tried that in a
branch as well, and I wasn't crazy about it (http://github.com/
giraffesoft/resource_controller/commits/automatic_route_discovery).
It's too much magic, too much generated code, too hard to understand
what's going on for anybody not familiar with the plugin. And, I'm
betting that it's pretty damn hard to debug too.

J.

I like Hampton's proposal - I think it covers a lot of cases, while
remaining relatively neutral in terms of what it expects.

I wholeheartedly concur.

The only things I'm not clear on is how it would cover polymorphism,
or cases where the association has a non-standard name. Sure, you
could override all the methods that it 'generates', but that would be
a pain, and not very DRY. It'd be nice to expose some methods like m_r
and my r_c do that would allow you to define the way objects,
collection, and associations are loaded for each level.

For polymorphism, sticking with Hampton's syntax, we'd end up with:

load [User, Project], [Project], [Account, Project]

.. which I'm not crazy about. I think something like:

resource_for Project # could be inferred from controller name if std
belongs_to x, y, [z, a] # args here are x, OR y OR z, a

...potentially replacing belongs_to with parents, or another
keyword...

I don't know, I kinda think this bloats the controller and ties it to
strictly to the model. If I think of my projects, it's probably 95%
standard (i.e. pluralized table names, etc. and no polymorphism) and I
guess it's not that much different for other people (correct me if I'm
wrong). And in the 5% where we actually deviate from the standard
case, we could easily handcode similar methods. I know that's not
ultra-DRY but this way the actual API stays clean and keeps it down to
a reasonable amount of magic while still covering most cases.

- Clemens

I'm not necessarily disagreeing.

However, without some hooks for overrides, and polymorphism, plugins
that do RESTful abstraction layers, like the ones mentioned in this
thread, will still be forced to write quite a bit of custom,
duplicated code in order to handle those cases. It would be nice to
merge all that duplicate code in to core, and let the plugins do the
truly magical stuff (abstracting entire actions, customization DSLs,
and even action inference based on routes).

...or maybe Hampton, Ian, and I should come up with a base plugin /
API that we base all of our plugins on?

...or maybe Hampton, Ian, and I should come up with a base plugin /
API that we base all of our plugins on?

You guys are bound to have a bunch in common, basic core stuff. Of
that set of features there's probably some stuff that still won't be
fit for inclusion in the core, but odds are there's a subset of that
which is. Whether that functionality is user-visible stuff or just
nice hooks, I don't know.

You guys are the experts, I'm sure you'll come up with some awesome stuff :).

This is full of win. +1

+1 and I look forward seeing the solution.

My point with all of this is to massively strip down the functionality
that is available in the plugins and just have an extremely simple
interface for the most basic, basic resource facilities in a
controller.

Sounds like a great plan. So what's basic?

(I'm the resources_controller guy, btw)

- crud: Hampton's proposal of generated cruddies looks really nice, is
easy to understand, and override (let's say you want to order your
messages by some param, you can just override messages). Handling non
standard names should be easy enough to handle

  load User, Message => {:as => :tweet}

# or, it might be nicer if spread over two lines?

  load User
  load Message, :as => :tweet

- scoping: leveraging AR's assocs to provide scoping. Also nicely
covered by Hampton's proposal. However, singleton vs collection
resources need different handling. In Hampton's example, perhaps:

  load User, Image => {:singleton => true}

# or

  load User
  load Image, :singleton => true

  # doesn't generate images, and generates this:
  def image
    user.image
  end

- polymorphism. Not obvious, as James points out. I use polymorphism
a lot, which is why I gave r_c the ability to load up the resources
differently depending on the route that invoked it. I guess people
might argue whether this is 'basic'. (From my perspective, I got sick
of writing the same comments controller over and over again.)

if this is regarded as a 'basic', then

  load :commentable, Comment

could do the trick.

To implement this sort of thing, r_c gleans info from the route that
invoked the controller, this means we need to introspect the route
that the controller was invoked with.

So, it looks like Hampton's proposal covers the 'has_many' resource
case, and should cover the 'has_one' case with a little tweaking, and
could handle non standard names. It seems that 'has_many :as', and
'has_one :as' would require something of a different nature (route
introspection). Perhaps for that reason alone, perhaps polymorphism
should not be regarded as basic?

I would be happy with this, because that's what plugins are for.

(polymorphism is a specific case of being able to nest resources at
arbitrary points - this problem is solved by the same technique. the
one images controller can service /users/:id/images /cats/:id/images)

But, if you think polymorphism should be regarded as basic...

Michael Koziarski wrote:

request.resource or something with the necessary bits and bobs to
introspect successfully.

This would be a great abstraction. r_c currently emulates this
behaviour, by abstracting the resources from the path (using the
routing code). This enables the polymorphic and nesting cases

In Rails, routing does some funky awesomeness to figure out the
mapping of url to controllers and params, but it throws (most of) that
work away before the controller is invoked. Having a resource
abstraction would be the container for passing around RESTful
resources, while being agnostic about how they were generated, and
what they map to.

On this last point, Chris Cruft, and other rc_ers have made the point
to me that they sometimes have restful controllers which don't have
ActiveRecords behind them (or have AR enclosing resources, but not at
the endpoints), it would be nice to have an ordered array of abstract
resources handed to the controller, and that request.resource would
be.

(btw. It just so happens I'm giving a talk at RailsConfEurope about
r_c, and how rails could help /.*resource.*/ plugin authors by passing
essentially request.resource to the controller. I shall watch this
thread in earnest - maybe I'll have to rewrite the damn thing. Yay
for rewriting the damn things!

Cheers,
Ian

Hi All,

> http://pastie.org/230474

I've used m_r, r_c and others, and while promising at start, I had to remove them because most of the time the defaults weren't the defaults as I want them to be and they became too obtrusive. The problem, as hampton already indicated, is that they try to do too much. In my case especially with regards to action behaviour. Not so much with regards to resource facilities.

What I do like about hamptons proposal is that he's indicating he wants the most basic resource facilities.

However, instead of baking this in the ActionController I think resources deserve to be first class citizens. This idea was actually born by Dan Yoder after long discussions on the Waves project. The term "resource controller" that most are using is a misnomer, the two should be decoupled imo.

I.e., when I do map.resources :posts, I would like to see this routed to:

  /app/resources/posts_resource.rb

This class would inherit or mixin a ResourceService (a term r_c uses).

There you would do the kind of magic that hampton suggests in his pastie and that is happening in all the plugins that have been plugged in this thread. You would think more in terms of the resources instead of in terms of the controller action. This is the place where you set up the resources required, where you define how a new resource is created, etc. All this would stay out of your controllers.

Once the resources are set up you go to your controllers. Just like views have access to the instance variables defined in a controller the controller would have access to the instance variables defined in the resource. This also makes controllers more re-usable for multiple resources, and gives greater potential for DRYness. Which is the other part that all these "resource controllers" are trying to solve. So instead of having a controller for every resource you could have just a few controllers (ideally just one). This again would highlight that controllers are about action, orchestration, driving behaviour, and not about managing resources.

Lawrence

What I do like about hamptons proposal is that he's indicating he wants
the most basic resource facilities.

Definitely, I think it's a great idea to come up with a nice
evolutionary enhancement to the resources code, along with some added
metadata for reflecting on what's going on.

However, instead of baking this in the ActionController I think
resources deserve to be first class citizens. This idea was actually
born by Dan Yoder after long discussions on the Waves project. The term
"resource controller" that most are using is a misnomer, the two should
be decoupled imo.

I think that this kind of experimentation should definitely take place
in a plugin. The controller + routes thing we have now works really
well, and some minor enhancements could well improve that. Something
larger like you're talking about here should be left in plugins till
it's had a chance to prove itself and get fully baked.

Yes, we did. You might also say that I badgered you about Full-circle
REST...

...

> "Full Circle REST" is where it's at.

Definitely, and I think we've discussed this previously on #rails-contrib?

...

So my main disagreement with the other arguments here is that they are
too simple for an initial feature. Originally, AR didn't support
Polymorphic and so I'm hesitant to spend too much time worrying about
it. I find I use polymorphic things in about 5% of my resources. Of
course, some projects require more polymorphism and others require 0%.
Just based on the requirements.

My main thoughts with this is that it defines a clean and simple API
and pattern for controllers with resources. And its a *starting
point*. After this kind of things gets acceptance (and is put through
heat) then I think solving more complex issues is the next step.

Most of the people reading this do very very advanced Rails
applications. And to be honest, I'm not concerned about us here. I
mean, I do want to solve my own problem, but I really want to give a
simple solution for a common problem and then build on that.

Even when it comes to has-one associations... they kind of suck. I
mean, maybe I'm just a lame developer, but I do a fuckload of projects
and I *rarely* find has-one to be required. Rarely, rarely, if ever.
I'd rather just break out of the stock REST controller and handle it.
Or, usually, I just fucking put it in the parent model.

I'm going to build this as a simple plugin. And no, it won't be
integrated into m_r. m_r handles more complex cases. This is for when
m_r is overkill.

-hampton.

This is awesome, and does a lot of what we talked about in this
thread: http://intridea.com/2008/7/28/fetches-bringing-your-actioncontroller-its-slippers

+1

I loved m_r for quite a while before dropping it because of huge
amount of magic and difficulty of the underlying code.

a super simple/transparent replacement would be great.