Closed paulmillr closed 12 years ago
If a route matches, the Router adds a path
to the params
. If this is present, it is used as URL, see ApplicationController
:
adjustURL: (controller, params) ->
if params.path
# Just use the matched path
url = params.path
else if typeof controller.historyURL is 'function'
# Use controller.historyURL to get the URL
# If the property is a function, call it
url = controller.historyURL params
The question is, when is path
not available and when comes historyURL
into play? In short, every time a controller is not invoked by a route. If you already have a model and want to pass it to a controller, you can start the controller directly with some params:
mediator.publish '!startupController', 'feeds', 'show',
feed: someExistingModel
some: 'options'
foo: bar
This is especially useful if there is a Collection at feeds#index
which already has the a full Feed
model and wants to call feeds#show
for it. This could be done via routing to /feeds/123
, but then the model would not be available instantly.
On moviepilot, our controllers have a conventional way to get the model data:
# Get the model data from JSON configuration or from params
#
# 1. Try to get the page data from configuration
# 2. Try to get an object from params
# 3. Fallback to a stub with an ID from params.id
getModelData: (params, key, idKey = 'id') ->
# Shortcut
config = MovieExplorerConfig
fromConfig = @getModelDataFromConfig key
if fromConfig
data = fromConfig
else if params[key]
data = params[key]
# If it’s already a model, unbox the attributes
if data instanceof MovieExplorer.Model
data = data.toJSON()
else if params[idKey]
data = id: params[idKey]
else
return null
In the specific controller, there’s getFeedData
which curries getModelData
so we can write:
@feed = new Feed @getFeedData(params)
If you go to http://moviepilot.com/movies/9040 directly, the model data is already present in the HTML as JSON, stored in the MovieExplorerConfig
object.
If we want to link to /movies/9040
from inside the application, most of the time we already have the movie model. So we just pass it via publish '!startupController', 'movies', 'show', movie: movieModel
. In this case, historyURL
is called to determine the right URL.
If we just got the ID from a matched route, the model will automatically fetch itself from the server.
I agree historyURL
stuff may be confusing since it’s not used when routes match, which is the normal case. The question is however how to build a proper URL when starting controllers directly. I find this feature very useful in a fully-encapsulated system since it allows controlled data sharing.
Of course, there could be other solutions to solve this, like a central factory which would return the model for a given ID. But by explicitly passing data to other controllers, we are able to dispose all other data immediately. And we don’t have to rely on central stores.
Closing this, but we should include this description in the Controller
documentation.
I'm not sure but it seems that it's useless.
For example:
What's its purpose in this case? User will be redirected to
feeds/
if he'll navigate to/
etc.