On Sep 20, 2007, at 3:18 PM, Ezra Zygmuntowicz wrote:
>
> Merb controllers cannot be modules because modules are not
> instantiatable. The way merb's thread safety works is by
> instantiating a new controller object for each new request/thread.
>
But under _ry's proposed system, there is still an object to
instantiate per request--it's just the action instead of the
controller that gets its own class.
From a software engineering perspective, I like the direction _ry is
going. The question he is raising seems to be, "What is the role of
a controller?" and on a related note, "What is the role of an action?"
I've seen very large controllers before, and they don't always make a
lot of sense as a single class. A typical controller will have a
bunch of public actions followed by a bunch of protected methods.
Except in very segmented areas of the website (e.g. an admin area),
each protected method is generally called once by one public action--
there is not always a lot of re-use going on; rather, factoring these
methods out seems to be a way of making the code in public actions
more readable.
In typical object-oriented design, we try to create classes that map
easily to real-world things or events. In this case, it seems that
an Action is a reasonable object class to consider. As _ry has
mentioned, Actions have:
- one or more route mappings
- security measures (e.g. you can see an object, but you have to be
logged in to edit it)
- object state (request parameters)
- multiple formats for the response
- multiple HTTP request method options (GET/POST etc.)
- before / after filters
_ry also mentioned that we currently instantiate controllers
primarily to call an action. It's possible that we could get a small
performance benefit by not having to perform a check on all of the
controller's before / after filters to see if they apply to the
action. Rather, an action would just be an Action object, and it
would make calls to other things in the initialize method (or
'before' method, see below). With this architecture, we could take
advantage of inheritance in the OO way (as well as map exceptions to
actions the OO way):
module Merb
class Action
def before; end
def after; end
end
end
class AdminAction < Merb::Action
def before
if User.find(session[:user_id]).admin?
# ok
else
# Raise the Unauthorized controller's NeedToLogin
action (class):
raise Unauthorized::NeedToLogin, "Please log in to the
admin area."
end
super
rescue ActiveRecord::RecordNotFound
raise InternalServerError::StaleSession
end
end
module Admin
module Products
class Show < AdminAction
def initialize
# ...
end
def before
# Add additional before filter code, then
# call AdminAction's before filter
super
end
def html_response
render
end
def after
# Do something else afterward
super
end
end
end
end
As a side-effect of not using before filters, we would be able to
simplify the code to re-load a class in development mode (the
complicated part comes when we have to remove constants so that
before filters don't get double- or triple-called).
I think _ry's ideas in this area are definitely worthy of discussion.
Duane Johnson
(canadaduane)
_______________________________________________
Merb-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/merb-devel