Enhancement - RADAR Architecture

Good morning,

I have an enhancement proposal for the REST handling in Rails.

I was wondering how to implement the RADAR architecture
(http://pragdave.pragprog.com/photos/uncategorized/2007/03/29/radar.png)
in a single Rails app: the idea would be to create two modules of
controllers, the first for the presentation ones (which interacts with
the website and renders views) and the second for the REST ones (for
more about RADAR architecture, see Dave Thomas post
http://pragdave.pragprog.com/pragdave/2007/03/the_radar_archi.html).

Show, Don’t Tell:

Let’s have a basic social website providing a user’s profile page: you
have infos about the guy, his events, his tags, his contacts, his
snippets & bookmarks too, etc. Building this website with the RADAR
architecture would mean:
   app/controllers/presentation/
    * profiles_controller.rb
   app/controllers/rest/
    * users_controller.rb
    * events_controller.rb
    * tags_controller.rb
    * contacts_controller.rb
    * snippets_controller.rb
    * bookmarks_controller.rb

The benefit: you have a REST application server which can be accessed to
get xml, rss, etc. and a ‘presentation’ layer which deals with the
website and queries the REST controllers.

This kind of design is not specific to particuliar applications. For
example, I have just finished writing a Ruby on Rails application for
doctors: it's accessible online through the presentation layer but also
through remote services thanks to the REST modules (see my snippets
below).

So, back to my example, the idea would be for the show
action of the profiles_controller to GET infos from the 6 ressources
from the module rest:

   profiles_controller.rb
   
     # GET presentation/profiles/1
     # GET presentation/profiles/1.xml
     def show
       @user = get rest/users/params[:id]
       @events = get rest/events/?attendee=params[:id]
       # ../..
     end

The result: you have clean controllers. All the authorization logic
(before_filter :authorize, :only => :destroy for instance) will be in the REST
modules so the presentation one is just designed to retrieve
informations from you different resources.
Moreover you have already an API for the core of your application (the
REST server).

Please tell me if I'm wrong but I think this sort of mocking requests
are not built-in since even render_component, for example, creates a new
request (through ActionController::Integration::Session &
ActionController::Integration#process; using it would be a pain
because it has lots of useless data in our case...).

Looking at the source code, the point would be to create a method which
instantiates @_request, @_params & @action_name and call
ActionController::Base#perform_action (just like
ActionController::Base#process without cookies, sessions, headers,
etc.).

For my application for doctors, I have done a method:
http://pastebin.via.ecp.fr/64 (see: http://pastebin.via.ecp.fr/65 for
usage). It relies on a new dummy format 'internal'. All my REST actions
respond to it and render text.

Back to my example:
    profiles_controller.rb
   
      # GET presentation/profiles/755
      # GET presentation/profiles/755.xml
      def show
        @user = users_get(params[:id])
        @events = events_get({:attendee_id => params[:id]})
        # ../..
      end

and the same with users_(put|delete|post). Those methods returns the body of the
respond_to, e.g.:
   class UsersController < ApplicationController
     def show
       ../..
       respond_to do |format|
         format.internal {render :text => @user.name}
       end
     end
   end

(this part would be application specific; your can render CSV, xml, or
whatever, following your own internal conventions to communicate with
the presentation layer)

Just a detail: unfortunately, I was not able to call
ActionController::Routing::Routes.recognize because it works on a real request.
So you have to call posts_get({:id => “42”}) instead of
get ‘posts/42.internal’ (kind of ugly).

I use this solution and it works (a little bit hackish however, you
might already be thinking of a better way to do such a thing).

What do you thing of building inside of Rails such methods to retrieve
informations? I'm pretty sure it will be a great enhancement for a
better design and to avoid controllers which mix CRUD & non-CRUD actions.

I wanted to open the discussion here to detail those points. If you
are interested in, I will open a [ENHANCEMENT] ticket on the trac.

Thank you for your great job!

Cheers,

I have an enhancement proposal for the REST handling in Rails.

I personally don't think this approach is worth the trouble unless you
have a scenario where you have many HTML UIs accessing the same base
model. Basically, this is the two-step view as defined by
http://www.martinfowler.com/eaaCatalog/twoStepView.html.

The common use case given is a airline ticketing system that's shared
by multiple airlines in an alliance. All use the same fundamental
system, but they each implement their own UI layer on top of it.

I don't see this as a generally applicable model for Rails. As in not
something "most people need most of the time". But do wrap this up as
a plugin that extends Rails in the points you feel are necessary to
support this better.

Thank you for your reply David.

I personally don't think this approach is worth the trouble unless you
have a scenario where you have many HTML UIs accessing the same base
model. Basically, this is the two-step view as defined by
http://www.martinfowler.com/eaaCatalog/twoStepView.html.

Actually it really cleans up your code, even in small 'standalone' (with
few HTML UIs) applications.

Considering REST just like the way to write your CRUD
actions seems somewhat weak. You might end up using the
scaffold_resource as a starting point for your controller and mess it up
with actions that they don't really fit in this scheme (ignoring the
concept of 'resource').
The presentation layer in web applications is as important as the
interaction with your DB. Emphasis should be on both side and the code
separated.

Anyway, that's interesting how the 'view' part seems always to be
painful. Compare the way you test your views compared to
unit testing for example :wink:

The common use case given is a airline ticketing system that's shared
by multiple airlines in an alliance. All use the same fundamental
system, but they each implement their own UI layer on top of it.

For example. But (sorry if I repeat myself) I'm convinced it helps even
in small applications to tidy up your code.

I don't see this as a generally applicable model for Rails. As in not
something "most people need most of the time". But do wrap this up as
a plugin that extends Rails in the points you feel are necessary to
support this better.

Sure, I will since I have recieved emails from people interested by the
idea.

See you in Portland,