goaltools / goal

Goal is a toolkit for high productivity web development in Go language in the spirit of Revel Framework that is built around the concept of code generation.
BSD 2-Clause "Simplified" License
87 stars 3 forks source link

Allocate parent controllers just once #41

Open ghost opened 8 years ago

ghost commented 8 years ago

Intro

There is a controller with its special action:

type GrandParent struct {
    Context map[string]interface{}
}

func (c *GrandParent) Before() http.Handler {
    println("This is GrandParent")
    c.Context = map[string]interface{}{}
}

The controller above is embedded by a number of other controllers.

type Parent1 struct {
    *GrandParent
}
type Parent2 struct {
    *GrandParent
}

Those controllers are embedded by our main controller.

type Child struct {
    *Parent1
    *Parent2
}

func (c *Child) Index() http.Handler {
}

Problem

The problem is the GrandParent controller will be allocated twice, meaning c.Parent1.GrandParent != c.Parent2.GrandParent. The output of the GrandParent's Before will be:

This is GrandParent
This is GrandParent

As a result, we cannot share a context between controllers of different levels of embedding.

Use-case

This is the problem I've faced trying to implement #39. There is controllers/errors controller that is responsible for rendering error pages. We embed it in our main controller and mount its actions to * /errors:

type Controllers struct {
    errors.Errors `@route:"/errors"`
}

Now if we want to pass some value to the actions of that Errors controller it doesn't work:

func (c *Controllers) Before() http.Handler {
    c.Context["someKey"] = "someValue"
}

Because, Context of Controllers and Context of Errors are different instances. But they must be pointers to the same object.

Expectations

A single allocation per object per request. Special (Before and After) actions must be called just once: Parents must have priority over their Children.

xpbliss commented 8 years ago

solve? How about the autoform?

ghost commented 8 years ago

This is ready. Right after I finish refactoring controllers I'll push all the commits (there are a lot of them). Autoform is still a high priority.

ghost commented 8 years ago

I'm thinking over this one as well. Should we allocate controllers? Isn't it too much magic? Especially when it comes to these single allocation rules. Can we come up with another solution for sharing state between actions of different controllers?

xpbliss commented 8 years ago

Glad to see the goal is still activate!