One of the distinguishing features of Ember is the heavy emphasis it puts on URLs. In many other frameworks, having separate URLs for separate screens is either lacking or is tacked on as an afterthought. In Ember, the router is the component that manages urls and transitions between them.

Ember Routing Guides: http://emberjs.com/guides/routing/(link)

Ember.Route class details: http://emberjs.com/api/classes/Ember.Route.html(link)

Here we will take a look at different ways of adding routes:

Dynamic Segments in Routes:

A dynamic segment is a portion of a URL that starts with a : and is followed by an identifier.

For example, if the dynamic segment is :offer_id, Ember.js is smart enough to know that it should use the model (with the ID provided in the URL).

// router.js
this.resource('offer', { path: '/:offer_id'});
// offer route
export default Ember.Route.extend({
  model: function(params) {
    return this.store.getById('offer', params.offer_id);
  }
});

More Details: http://emberjs.com/guides/routing/defining-your-routes/#toc_dynamic-segments(link)

Access Parent Models in Child Route:

It returns the model of a parent (or any ancestor) route in a route hierarchy. During a transition, if a route needs access to a parent route's model (or just reuse the model from a parent), it can call this.modelFor(theNameOfParentRoute) to retrieve it.

  // router.js
  this.resource('offer', { path: '/offer/:offer_id'}, function(){
    this.route('delivery_details');
  }
  // delivery_details route
  model: function() {
    var offerId = this.modelFor('offer').get('id');
    return this.store.getById('offer', offerId);
  }

Access query-params of other route:

It retrieves parameters, for current route using the state.params variable using the supplied routeName. paramsFor returns hash of query-parameters or dynamic-segments passed in specified route-name.

  model: function() {
    var offerId = this.paramsFor('offer').get('id');
    return this.store.getById('offer', offerId);
  }

Use different controller:

The name of the controller to associate with this route.

By default, Ember will lookup a route's controller that matches the name of the route. However, if you would like to define a specific controller to use, you can do so using this property.

  // session route want to use 'authenticate' controller
  export default Ember.Route.extend({
    controllerName: 'authenticate'
  });

Use different template:

The name of the template to associate with this route.

  // offer/supervisor_messages route (same controller but different template)
  renderTemplate: function() {
    this.render('message_template', {controller: 'offer.supervisor_messages'});
  },

If you are using two different outlets in same template, then you can use it following way:

  // inbox template
  
{{outlet "appMenuList"}} {{outlet}}
  // inbox route
  renderTemplate: function() {
    this.render(); // default template
    this.render('appMenuList', {
      into: 'inbox', // template-name
      outlet: 'appMenuList', // outlet-name
      controller: 'application'
    });
  }

Use of afterModel hook

This hook is called after this route's model has resolved. It follows identical async/promise semantics to beforeModel but is provided the route's resolved model in addition to the transition, and is therefore suited to performing logic that can only take place after the model has already resolved.

// confirm-order route
  model: function(){
    return this.store.all('book_order').get('lastObject');
  },

  afterModel: function(order) {
    if(!order) {
      this.transitionTo('delivery.book_order');
    }
  }

In above example, we first look for 'deliver-order' object, if its present then redirect to confirm-order route. But if its empty then redirect to 'book_order' route.

Use of beforeModel hook:

This hook is the first of the route entry validation hooks called when an attempt is made to transition into a route or one of its children. It is called before model and afterModel, and is appropriate for cases when:

  1. A decision can be made to redirect elsewhere without needing to resolve the model first.
  2. Any async operations need to occur first before the model is attempted to be resolved.

For ex: validate user can visit protected url by verifying whether he is signed in or not.

beforeModel: function(transition) {
    if (!this.controllerFor('application').get('isLoggedIn')) {
      alert('You must log in!');
      var loginController = this.controllerFor('login');
      loginController.set('attemptedTransition', transition);
      this.transitionTo('login');
    }
  },