How to Remove the Hash From Angular Routes in Rails
When building client-side applications, your URLs are prepended with a hash. Removing this can make your routes more user-friendly and more easily crawled by search engines. Here is how you can remove the hash from your routes in an Angular app built on Ruby on Rails, and use the standard URL structure.
Step 0: Our example Application
We’ll look at a recipe site for our example application. In our application, we’ll have a homepage, a recipe route that shows us all of the recipes, and a route for single recipes. Here is our application configuration:
var app = angular.module("recipeapp"); app.config(["$routeProvider",function($routeProvider) { $routeProvider .when("/", { templateUrl: "templates/index.html", controller: "IndexController" }) .when("/recipes/, { templateUrl: "templates/recipes.html", controller: "RecipesController" }) .when("/recipes/:id", { templateUrl: "templates/recipe_show.html", controller: "RecipeShowController" }); }]);
Step 1: Remove The Hash
First, we will enable [HTML5 Mode] in our AngularJS application. This will remove the hash from our URLs. Include $locationProvider
in your module’s configuration, and set the mode to true.
app.config(['$routeProvider','$locationProvider', function($routeProvider, $locationProvider) { $locationProvider.html5mode(true); // ... }]);
Step 2: Configure Rails To Handle Angular Routes
The above will work for cases when the user navigates from one part of the AngularJS application to another. However, if they try to navigate directly, they will get an error. If the user tries to navigate to /recipes/1
directly or hits refresh on that page, the request is sent to the Ruby on Rails router instead of Angular.
To fix this, we need to capture those requests. In you app/config/routes.rb
at the end:
get '/\*path' => redirect('/?goto=%{path}')
This will cause any uncaught routes to get redirected as a query string, which will be passed to the Angular router.
Step 3: Handle Rails Redirects
Angular needs to know how to handle these routes, so we will add a call to the otherwise()
method of $routeProvider
:
$routeProvider.otherwise({ redirectTo: function(current, path, search) { if(search.goto) { return '/' + search.goto; } return '/' } });
Now any URL will get redirected to Angular, which will handle the route. This way you don’t have to maintain two lists of routes, and you can use standard URL formats in your application.