This is looking even better with respect to Rails 3 features. In particular, ExceptionNotification seems to be another rack middleware. With the above design, many modular additions can go in middleware placed into this MVC card stack.
I'm also thinking that Notifications have all the structure we need Hooks, so those are sort of redundant: http://railscasts.com/episodes/249-notifications-in-rails-3
--Gerry Gleason.....Sat Jun 11 09:31:28 -0700 2011
Now that I'm implementing parts of this, maybe I'll add some more concreate API info here as it is designed.
--Gerry Gleason.....Fri Nov 18 04:23:30 -0800 2011
little confused about the api above. looks like you're setting instance variables in a class method (self.new). are those supposed to be in #initialize?
--Ethan McCutchen.....Sat Nov 19 12:19:09 -0800 2011
Yeah, that's wrong, it should be an initialize method
--Gerry Gleason.....Mon Nov 21 08:11:28 -0800 2011
Some notes on the emerging implementation:
Some of the argument passing has to be worked out so that you can put in alternatives to each component, but basically you have what is in the diagram where each MVC component has a Rack interface. We add ourselves in a builder stack with this in config/application.rb:
This is the controller component, and it gets the Rails app as defined in config/routes.rb, plus an optional modelapp, which it creates with CardController.new by default. Right now we ignore the return from this, but technically we should always return a valid rack response. Finally we call the Rails app. The rails part of this is pretty thin. The matches? method used by constraints does the final setup of params based wagn.* args and matching (return true) if wagn.action was set in the pre-processing. That takes use to application#all which does the rendering for all cases.
So, M is in CardController (I think this can be a Metal app since we don't use much Rails here),
V is in ApplicationController (as the Rails App in routes.rb), and
C is config/application.rb
We can split out the Rack parts of config/application.rb into another file for clarity and better separation.
--Gerry Gleason.....Mon Nov 28 07:58:14 -0800 2011
There are some really stark distinctions about what you can do at in each component. In C, you pretty much are just changing things in the env hash, adding wagn.* variables. The little bit in matches? is to access params because it is here that we have it first as a "request", which includes the env. As mentioned, we ignore the return from M, but it can set wagn.render and wagn.status and that will control the View, but it is the only stage that can access the model. V can use the model, but only via wagn.card as loaded and modified in the M component.
--Gerry Gleason.....Mon Nov 28 08:08:33 -0800 2011
I just realized that we have been thinking about part of this all wrong. Or maybe more that we've missed something. We've left out the idea of sessions, which connects to CRUD via permissions. The upshot is that what that account controller does isn't CRUD, but there are model actions. The linking to the second table and hence the AR model will go away, but setting and clearing the session (sign-in, sign-out) needs to be handled as model actions. I think it could even be CRUD semantics, but for the 'active session'. Sign-in is then create session, Sign-out is delete. You implicitly read the session in permission checks. (We could add "log-in as another user" as update, then allowing 'create_and_update' for sessions would mean you could 'signin' again and it would replace your session. I guess the way we use it, session is a singleton object, where both wagns and cards are at least potentially collections.
--Gerry Gleason.....Sat Dec 03 03:26:40 -0800 2011
Mechanically, a cookie or other feature connects the network session to a session object, which is part of the request by the time we get it. Another middleware does network session to session object mapping, so the current session (or none) is something externally supplied. The card CRUD actions read the current session to get the validation actor for permission checks. The sign-in, sign-out actions do not update the session, they add and remove the network session in the authentication layer. When another request comes from a source that just signed out, the current session will be empty, when they sign in again, the next request has that session set to the new user.
I think this means that 'current_user' needs to always come directly from the request, and if we want to store it or related values not already in rack variables, use env['wagn.session'] or 'wagn.current' if you like that better. We will have to clear up some details about 'as_user' and administrative tasks that run without a session. In scripts, often anon becomes wagbot directly, which is different than when that happens for a normal request doing as 'as' operation. We might even consider the system user (gerry, root) as the session for scripts to complete the chain of session ownership.
--Gerry Gleason.....Sat Dec 03 04:05:16 -0800 2011
There are lots of cases where the as_user thing is a bit of a hack, but others where it's quite important, and I think more of those will happen. For example, I think we really want an administrator to be able to see any page *as it would look to a given user*.
I don't think this violates the idea of the current_user always coming directly from the request, but it means that, as is currently the case, we rarely refer directly to the current_user, preferring the as_user (which in normal circumstances falls back to the current_user).
--Ethan McCutchen.....Sat Dec 03 08:59:10 -0800 2011
btw, I think we're going to want a wagn.config that basically takes settings directly from the yaml file that's going to replace wagn.rb
--Ethan McCutchen.....Sat Dec 03 09:18:16 -0800 2011
The exploration of these ideas is still on the 'rackish' branch, and it has been kept pretty much in sync with traits.
--Gerry Gleason.....Tue May 22 15:03:01 +0000 2012