Ember render 404 with Invalid URL Slugs

2019-09-01 05:30发布

I'm using dynamic URLs in my application for easy readability. The url structure is /[:organization_slug]/[:product_slug]. In other words, an organization is the owner of a product. For security purposes, I want to display a 404 when somebody types an organization in the URL when it doesn't exist. Also similarly, display a 404 when a product that doesn't exist is entered into the URL.

I've implemented the Ember 404 as described in this post. Then, I'm hooking into afterModel to see if the query returned a record and trying to transition into the fourOhFour route if not. Here is my relevant code currently:

router.js

Router.map(function() {
  this.route("fourOhFour", {path: "*path"});
  this.resource('organization', {path: ':organization_slug'}, function() {
    this.resource('product', {path: ':product_slug'});
  });
});

routes/organization.js

var OrganizationRoute = Ember.Route.extend({
  model: function(params) {
    return this.store.find('organization', {slug: params.organization_slug});
  },
  afterModel: function(organization, transition) {
    if(organization.get('length') === 0) {
      //If it's not a correct URL render the 404
      this.transitionTo("fourOhFour");
    }
  },

  serialize: function(model) {
    return {organization_slug: model.get('slug')};
  }
});

export default OrganizationRoute;

routes/product.js

var ProductRoute = Ember.Route.extend({
  model: function(params) {
    var self = this;
    // Verify that the product belongs to the organization in the URL
    return this.store.find('organization', {slug: Ember.organizationSlug}).then(function(organization) {
      var organizationID = organization.get('firstObject.id');
      return self.store.find('product', {slug: params.product_slug, organization: organizationID});
    });
  },
  afterModel: function(product) {
    if(product.get('length') === 0) {
      this.transitionTo("fourOhFour");
    }
  },
  serialize: function(model) {
    return {product_slug: model.get('slug')};
  }
});

export default ProductRoute;

The problem is that the transition is not firing. The route is not activating and the template is not being rendered. I think this has something to do with the fact that the route exists due to the nature of the dynamic URL. However, I want to maintain the URL path but display the 404 template, which is not working properly. If I change the path of the 404 route to a static string like /404 the transition works. However, I'd like to keep the URL path of the original request if possible.

That way, if someone requests a route that actually doesn't exist (i.e. /foo/bar/baz), it will look identical to a page where the route is valid but the record does not exist. Can anyone point me in the right direction?

Thanks in advance!

1条回答
姐就是有狂的资本
2楼-- · 2019-09-01 06:13

I believe your issue is that when you are trying to transition into a "catch all", Ember.js has no idea what that is. This is easy to fix as transitionTo() takes a 2nd parameter for specifying the model, which in your case would be the URL.

So, for a non-existent product, your route would look something like this:

App.BadRoute = Ember.Route.extend({
  model: function(){
    return "abcdproduct";
  },
  afterModel: function(badProduct){
    this.transitionTo('notFound', badProduct);
  }
});

See a basic working example here

查看更多
登录 后发表回答