What is the best practice for save the target path to go to it after registration?

Problem:

I have a rout that requires authentication. In after model callback I redirect not authenticated user to the login route. Users can register on this route. After registration a user should confirm email. And after confirmation I should redirect user to requested route. I try save current route in afterModel hook (before redirect to login) in localStorege. but I can’t serialize transitation object or get requested url

Environment

  • ember 1.10 + simple-auth
  • rails 4.1 + devise

Read this page: Preventing and Retrying Transitions - Routing - Ember Guides

Section you want is called “STORING AND RETRYING A TRANSITION”

It is not help to me. It is working only user sign in (not sign up). When user registers and clicks a link from a confirmation email, new instnce of ember app will be loaded and loginController will not have property ‘previousTransition’

On May 20, 2015, at 8:18 AM, max_konin noreply@emberjs.com wrote:

It is not help to me. It is working only user sign in (not sign up). When user registers and clicks a link from a confirmation email, new instnce of ember app will be loaded and loginController will not have property ‘previousTransition’

Sounds like the link in the email needs to send them where they want to go, instead of the app root. So you could change the link, or embed the destination in a cookie which would picked up on the next access to the site, or store it in a session which persists for a while (which of course would require a session id in the link or a cookie).

Yes, I understand. But I can’t get the requested URL in afterModel callback before redirection on the login route

The example on the site says, you should use beforeModel hook, not afterModel.

How can I get requested URL in beforeModel?

I think you can get at least route name like this:

afterModel: function(model, transition) {
  console.log(Ember.get(transition, 'targetName'));
}

But targetName returns ember’s route name. it will work only if route is static. But if route has dynamic segment (/order/:id) it isn’t working, because I should save params beside the route’s name. And There are more complicated cases. For example, route may be nested to another routes with params or has queryParms.

I would be very happy if I had property ‘targetUrl’ in transition. Or if I could serialize transition’s object to JSON, save it in localStorage and deserialize

1 Like

Just check Transition object in Ember source. There are params also:

Transition.prototype = {
  targetName: null,
  urlMethod: 'update',
  intent: null,
  params: null,
  pivotHandler: null,
  resolveIndex: 0,
  handlerInfos: null,
  resolvedModels: null,
  isActive: true,
  state: null,
  queryParamsOnly: false,

  isTransition: true,

I think you can probably resolve route using a router object to get real URL.

In a nutshell:

  1. If they aren’t authenticated, send them to registration/login with queryParams:
this.transitionTo('login', {
   queryParams: { path: location.pathname }
});
  1. In the controller for registration/login, you’ll need a queryParam defined for the path you’ve provided:
queryParams: ['path'],
  1. Setup your redirect:
actions: {
    authenticate: function() {
      var adapter = this.store.adapterFor('application');
      var url = adapter.buildURL('login');
      var self = this;

      adapter.ajax(url, 'POST', {
        data: {
          email: this.get('email'),
          password: this.get('password')
        }
      }).then(function() {
        self.transitionToRoute(self.get('path') || 'dashboard');
      });
...

Now, after authenticating, the user will be redirected to the original path.

Not sure if this is the “best practice” though. This is just the way I solved it.

It doesn’t work because location.pathname returns previous url, not url for requested route

1 Like

location.pathname is the location of where you landed. within that route is where you transition out and you save it by passing it as a query parameter.

scenario:

  1. user attempts to go to /loans which requires authentication
  2. user is redirected to /login?path=%2Floans
  3. user authenticates then goes to the path if its defined (/loans in this case)

this logic currently works in our 1.9 app

You have access to the router on the transition object, transition.router, which means you have access to this method.

Pass it the targetName, and an optional object which can represent the dynamic portions of the url, which will resolve to a URL string.

JS Bin - Collaborative JavaScript Debugging fiddle showing how the method works with params.

1 Like

3 years later, and as far as I can tell, still no reliable/easy way to get the URL from from the Transition object.

Without any documentation, it’s hard to figure out how to use the generate method. Here’s an answer on stackoverflow that has working example invocation.

Personally, I simplified this approach with some lodash methods:

    let params = merge({}, ...values(transition.params));
    let url;
    if(isEmpty(params)) {
      url = transition.router.generate(transition.targetName);
    } else {
      url = transition.router.generate(transition.targetName, params);
    }

(generate gets angry if you pass it {} for params)

Here’s how I’m solving this problem in 2020 (Ember 3.17):

  async beforeModel(transition) {
    try {
      this.auth = await this.fetchAuthentication()

      const returnToRoute = window.localStorage.getItem('redirect-on-login')
      if (returnToRoute) {
        window.localStorage.removeItem('redirect-on-login')
        this.transitionTo(returnToRoute)
      }
    } catch (err) { // user is not authenticated
      window.localStorage.setItem('redirect-on-login', transition.intent.url)
      this.transitionTo('enroll')
    }
  }

Just looking at the docs and this could work?

RouterService