Assignment of Spine.Stack controllers to Spine.Manager instance leads to conflicts
vail130 opened this issue · comments
If an application has a controller with key "manager" in its Stack, then the instantiation of the Stack overwrites the Stack instance's "manager" property with an instance of the controller named "manager" managed by the Stack.
Stack example with conflict:
class App.Stack extends Spine.Stack
controllers:
manager: App.Manager
Here's where it happens (manager.coffee lines 64 - 68):
@manager = new Spine.Manager
for key, value of @controllers
@[key] = new value(stack: @)
@add(@[key])
Here's a link to the code in the repo:
https://github.com/maccman/spine/blob/master/src/manager.coffee#L67
Looking for opinions, do we document this as a GOTCHA or add some code to dodge it?
A couple options I can think of:
- Find/replace
@manager
to@_manager
or something. - Throw an error to make "manager" a reserved key.
What about keeping all controller instances in an object in the context object rather than directly in the context object? For example:
for key, value of @controllers
@instances[key] = new value(stack: @)
@add(@instances[key])
...
@instances[@default].active() if @default
Good call @vail130
The basic usage of Stacks allows for people to use the stack instance as a way to access the created controllers. I think adding another variable for the collection would potentially break code for a lot of users out there. Here's the example from the spine docs...
class PostsShow extends Spine.Controller
class PostsEdit extends Spine.Controller
class Posts extends Spine.Stack
controllers:
show: PostsShow
edit: PostsEdit
posts = new Posts
posts.show # <PostsShow>
posts.show.active()
posts.show.isActive() # true
posts.edit.isActive() # false
This would change it to..
posts.instances.show.active()
posts.instances.show.isActive()
posts.instances.edit.isActive()
I think changing the @manager
variable to another name name like @_manager
might be the easier approach. I'm not sure if there are actual use cases of using the manager property of a stack instance?
Good point @cengebretson :)
I've only been using stacks with the built-in routing so I didn't think of this use case...
I'm not sure if there are actual use cases of using the manager property of a stack instance?
I do this in one of my stacks to bind to the 'change'
event:
constructor: ->
super
@manager.bind 'change', @changed
So far it looks like making @manager
a reserved key might be the most backward-compatible solution...?
Yeah, @cengebretson definitely makes a good point. In that case, there are a bunch of other instance variables and methods in Spine.Stack that need to be reserved:
manager, controllers, add, default, append, routes, route
New link for convenience: https://github.com/spine/spine/blob/master/src/manager.coffee#L67
Instead of hard-coding reserved keys, how about something like this?:
@manager = new Spine.Manager
for key, value of @controllers
throw Error "'@#{ key }' already assigned - choose a different name" if @[key]?
@[key] = new value(stack: @)
@add(@[key])
@adambiggs I like
seems like we could solve #232 with this as well
@adambiggs That looks good; it certainly would have saved me a headache the first time I ran into the issue.
I'll send a pull request for this tomorrow.
I think throwing an error is fairly easy/good solution. I can see where it would be a tough error to catch for somebody new to spine and they accidentally use one of the properties of a class as a controller name.
I think a similar situation comes up with models and defining attributes. When the model is converted to json the @attributes
method is called which will loop over values in the constructor.attributes array and call @[key]
. If the user has attribute names like url
or save
I could see it causing some headaches or interesting side effects.
attributes: ->
result = {}
for key in @constructor.attributes when key of this
if typeof @[key] is 'function'
result[key] = @[key]()
else
result[key] = @[key]
result.id = @id if @id
result
I see there is one issue #324 about this type of behavior coming up, not sure how often this has come up for others. Anyone have any opinions if this is something worthwhile to catch and at the lest, throw an Error message.